*****************************************************************************
**#           Borderline Democracy? The Electoral Consequences            ***
***     of the 2021 State of Emergency on the Poland-Belarus Border       ***
***                                                                       ***
***                     Paweł Charasz and Anil Menon                      ***
***                                                                       ***
***                          REPLICATION CODE                             ***
*****************************************************************************


*****************************************************************************
**#                               SET UP                                  ***
*****************************************************************************

version 18
clear all

global reps = 10000 // Set the number of replications for randomization

frames rename default data2023
frames create data2015_2019
frames create data2019_2023
frames create data2019
frames create commuters2021

*****************************************************************************
**#                           2023 DATAFRAME                              ***
*****************************************************************************

use "Data\polling_stations_data2023_geocoded.dta", clear

* Merge with 2023 election results
merge 1:1 teryt_gminy polling_station_no2023 using "Data\Elections\results_sejm2023.dta"
drop if _merge == 2 // drop non-permanent and foreign wards
drop _merge

* Dummies and labels for each sejm district
levelsof sejm_district2023, local(levels)
foreach level of local levels {
    local varname = "parl_district`level'"
    generate byte `varname' = sejm_district2023 == `level'
    label variable `varname' "=1 if sejm_district2023=`level'"
}

* Gen vars for 2023
gen turnout2023 = ballots2023/voters2023
gen vote_share_pis2023 = votes_pis2023/votes_valid2023
gen vote_share_ko2023 = votes_ko2023/votes_valid2023
gen vote_share_nowalewica2023 = votes_nowalewica2023/votes_valid2023
gen vote_share_konfed2023 = votes_konfed2023/votes_valid2023
gen vote_share_trzeciadrog2023 = votes_trzeciadrog2023/votes_valid2023
gen vote_share_left_oppo2023 = vote_share_ko2023 + vote_share_nowalewica2023 + vote_share_trzeciadrog2023
gen vote_share_right_oppo2023 = vote_share_konfed2023
gen nonregistered_share2023 = nonregistered_voters2023/ballots2023

* Label vars
label var vote_share_nowalewica2023 "NOWA LEWICA Vote Share in 2023"
label var vote_share_konfed2023 "KONFEDERACJA Vote Share in 2023"
label var vote_share_trzeciadrog2023 "TRZECIA DROGA Vote Share in 2023"
label var vote_share_ko2023 "KOALICJA OBYWATELSKA Vote Share in 2023"
label var vote_share_pis2023 "PiS Vote Share in 2023"
label var turnout2023 "Turnout in 2023"
label var nonregistered_share2023 "Non-Resident Voter Share in 2023"
label var vote_share_left_oppo2023 "Left Opposition Vote Share in 2023"
label var vote_share_right_oppo2023 "Right Opposition Vote Share in 2023"

*****************************************************************************
**#                          2019-2023 DATAFRAME                          ***
*****************************************************************************

frames copy data2023 data2019_2023, replace
frame change data2019_2023

** Merge with 2019-2023 crosswalk - Belarus Border
merge 1:1 polling_station_id2023 using "Data\Crosswalks\crosswalk_2019_2023.dta", nogen keepusing(polling_station_id2019 matched)

** Merge with 2019-2023 crosswalk - Ukraine Border
merge 1:1 polling_station_id2023 using "Data\Crosswalks\crosswalk_2019_2023_ukraine.dta", nogen keepusing(polling_station_id2019 matched) update

drop if matched == . // remove those unmatched due to 30 km distance cutoffs
drop if matched == 0 // remove those unmatched due to boundary changes / distance cutoffs
drop matched
drop if abs(dist_to_treated_boundary) > 30 & abs(dist_to_ukr_placebo_boundary2023) > 30

** Collapse
collapse (first) polling_station_id2023 (mean) dist_to_treated_boundary2023 dist_to_ukr_placebo_boundary2023 lat lon (sum) ballots2023 votes_trzeciadrog2023 votes_pis2023 votes_ko2023 votes_nowalewica2023 votes_konfed2023 votes_valid2023 population2023 voters2023 nonregistered_voters2023, by(polling_station_id2019)

** Merge with 2019 districts
merge 1:1 polling_station_id2019 using "Data\polling_stations_data2019_geocoded.dta", keepusing(teryt_gminy gmina_name polling_station_no2019 population2019 sejm_district2019 treated2019 partial_treated2019 ukraine_placebo2019 ukraine_placebo_partial2019 constituency_urban)
drop if _merge == 2
drop _merge

** Merge with 2019 election results
merge 1:1 teryt_gminy polling_station_no2019 using "Data\Elections\results_sejm2019.dta"
drop if _merge == 2
drop _merge

* Gen vars for 2019
gen turnout2019 = ballots2019/voters2019
gen vote_share_psl2019 = votes_psl2019/votes_valid2019
gen vote_share_pis2019 = votes_pis2019/votes_valid2019
gen vote_share_ko2019 = votes_ko2019/votes_valid2019
gen vote_share_sld2019 = votes_sld2019/votes_valid2019
gen vote_share_konfed2019 = votes_konfed2019/votes_valid2019
gen vote_share_left_oppo2019 = vote_share_ko2019 + vote_share_sld2019 + vote_share_psl2019
gen vote_share_right_oppo2019 = vote_share_konfed2019
gen nonregistered_share2019 = nonregistered_voters2019/ballots2019

* Gen vars for 2023
gen turnout2023 = ballots2023/voters2023
gen vote_share_pis2023 = votes_pis2023/votes_valid2023
gen vote_share_ko2023 = votes_ko2023/votes_valid2023
gen vote_share_nowalewica2023 = votes_nowalewica2023/votes_valid2023
gen vote_share_konfed2023 = votes_konfed2023/votes_valid2023
gen vote_share_trzeciadrog2023 = votes_trzeciadrog2023/votes_valid2023
gen vote_share_left_oppo2023 = vote_share_ko2023 + vote_share_nowalewica2023 + vote_share_trzeciadrog2023
gen vote_share_right_oppo2023 = vote_share_konfed2023
gen nonregistered_share2023 = nonregistered_voters2023/ballots2023

* Structure data as panel 
reshape long ballots vote_share_pis vote_share_left_oppo vote_share_right_oppo turnout voters population nonregistered_share, i(polling_station_id2019) j(Year) 
xtset polling_station_id2019 Year, delta(4)
sort polling_station_id2019 Year
gen diff_vote_share_pis = d.vote_share_pis 
gen diff_vote_share_left_oppo = d.vote_share_left_oppo 
gen diff_vote_share_right_oppo = d.vote_share_right_oppo 
gen diff_turnout = d.turnout
gen diff_nonreg_share = d.nonregistered_share

* Labels vars
label var Year "Year"
label var vote_share_pis "PiS Vote Share"
label var vote_share_psl2019 "PSL Vote Share in 2019"
label var vote_share_ko2019 "KOALICJA OBYWATELSKA Vote Share in 2019"
label var vote_share_sld2019 "SLD Vote Share in 2019"
label var vote_share_konfed2019 "KONFEDERACJA Vote Share in 2019"
label var vote_share_ko2023 "KOALICJA OBYWATELSKA Vote Share in 2023"
label var vote_share_nowalewica2023 "NOWA LEWICA Vote Share in 2023"
label var vote_share_konfed2023 "KONFEDERACJA Vote Share in 2023"
label var vote_share_trzeciadrog2023 "TRZECIA DROGA Vote Share in 2023"
label var diff_vote_share_pis "Change in PiS Vote Share"
label var diff_nonreg_share "Change in Non-Resident Voter Share"
label var diff_vote_share_left_oppo "Change in Left Opposition Vote Share"
label var diff_vote_share_right_oppo "Change in Right Opposition Vote Share"
label var diff_turnout "Change in Turnout"
label var vote_share_left_oppo "Left Opposition Vote Share"
label var vote_share_right_oppo "Right Opposition Vote Share"
label var turnout "Turnout"
label var population "Population Within Polling Station's Catchment Area"
label var voters "Registered Voters Within Polling Station's Catchment Area"
label var dist_to_treated_boundary2023 "Dist. to Treatment Boundary (km)"
label var dist_to_ukr_placebo_boundary2023 "Dist. to Placebo Treatment Boundary (km)"
label var polling_station_id2023 "Unique ID of 2023 Polling Station"
label var lat "Latitude"
label var lon "Longitude"
label var ballots "Number of Ballots Issued to Voters"
label var nonregistered_share "Non-Resident Voter Share"
label var votes_trzeciadrog2023 "Votes for TRZECIA DROGA (POLSKA 2050 + PSL) in 2023"
label var votes_pis2023 "Votes for PIS in 2023"
label var votes_ko2023 "Votes for KOALICJA OBYWATELSKA in 2023"
label var votes_nowalewica2023 "Votes for NOWA LEWICA in 2023"
label var votes_konfed2023 "Votes for KONFEDERACJA in 2023"
label var votes_valid2023 "Number of Valid Votes in 2023"
label var nonregistered_voters2023 "Number of Voters Voting Based on an Attestation in 2023"

* Dummies and labels for each sejm district
levelsof sejm_district2019, local(levels)
foreach level of local levels {
    local varname = "parl_district`level'"
    generate byte `varname' = sejm_district2019 == `level'
    label variable `varname' "=1 if sejm_district2019=`level'"
}

*****************************************************************************
**#                            2019 DATAFRAME                             ***
*****************************************************************************

frame change data2019
use "Data\polling_stations_data2019_geocoded.dta", clear
keep teryt_gminy polling_station_no2019 population2019 sejm_district2019 treated2019 partial_treated2019 ukraine_placebo2019 ukraine_placebo_partial2019 dist_to_treated_boundary2019 dist_to_ukr_placebo_boundary2019 lat lon constituency_urban
merge 1:1 teryt_gminy polling_station_no2019 using "Data\Elections\results_sejm2019.dta"
drop if _merge == 2
drop _merge

replace treated2019 = 0 if treated2019 == .
replace partial_treated2019 = 0 if partial_treated2019 == .
replace ukraine_placebo2019 = 0 if ukraine_placebo2019 == .
replace ukraine_placebo_partial2019 = 0 if ukraine_placebo_partial2019 == .

gen turnout2019 = ballots2019/voters2019
gen vote_share_psl2019 = votes_psl2019/votes_valid2019
gen vote_share_pis2019 = votes_pis2019/votes_valid2019
gen vote_share_ko2019 = votes_ko2019/votes_valid2019
gen vote_share_sld2019 = votes_sld2019/votes_valid2019
gen vote_share_konfed2019 = votes_konfed2019/votes_valid2019
gen vote_share_left_oppo2019 = vote_share_ko2019 + vote_share_sld2019 + vote_share_psl2019
gen vote_share_right_oppo2019 = vote_share_konfed2019

* Dummies and labels for each sejm district
levelsof sejm_district2019, local(levels)
foreach level of local levels {
    local varname = "parl_district`level'"
    generate byte `varname' = sejm_district2019 == `level'
    label variable `varname' "=1 if sejm_district2019=`level'"
}

* Labels
label var vote_share_konfed2019 "KONFEDERACJA Vote Share in 2019"
label var vote_share_ko2019 "KOALICJA OBYWATELSKA Vote Share in 2019"
label var vote_share_pis2019 "PiS Vote Share in 2019"
label var vote_share_psl2019 "PSL Vote Share in 2019"
label var vote_share_sld2019 "SLD Vote Share in 2019"
label var turnout2019 "Turnout in 2019"
label var vote_share_left_oppo2019 "Left Opposition Vote Share in 2019"
label var vote_share_right_oppo2019 "Right Opposition Vote Share in 2019"

*****************************************************************************
**#                          2015-2019 DATAFRAME                          ***
*****************************************************************************

frame change data2015_2019

use "Data/polling_stations_data2015.dta", clear
merge 1:1 teryt_gminy polling_station_no2015 using "Data\Elections\results_sejm2015.dta"
drop if _merge == 2
drop _merge

* Merge with 2015-2019 crosswalk
merge 1:1 polling_station_id2015 using "Data\Crosswalks\crosswalk_2015_2019.dta", nogen keepusing(polling_station_id2019 matched)

* Merge with 2015-2019 crosswalk: Ukraine placebo
merge 1:1 polling_station_id2015 using "Data\Crosswalks\crosswalk_2015_2019_ukraine.dta", nogen keepusing(polling_station_id2019 matched) update

drop if matched != 1 // Remove those polling stations that cannot be matched across 2015 and 2019
drop matched

* Collapse
collapse (sum) population2015 voters2015 ballots2015 nonregistered_voters2015 votes_valid2015 votes_pis2015 votes_po2015 votes_razem2015 votes_korwin2015 votes_psl2015 votes_lewica2015 votes_kukiz2015 votes_now2015 votes_jow2015 votes_stonoga2015 votes_ruchspol2015 votes_zjedsla2015 votes_so2015 votes_braun2015 votes_knp2015 votes_mn2015 votes_obyw2015, by(polling_station_id2019)

* Merge with 2019 districts
merge 1:1 polling_station_id2019 using "Data\polling_stations_data2019_geocoded.dta", keepusing(teryt_gminy gmina_name polling_station_no2019 population2019 voters2019 sejm_district2019 treated2019 partial_treated2019 ukraine_placebo2019 ukraine_placebo_partial2019 dist_to_treated_boundary2019 dist_to_ukr_placebo_boundary2019 lat lon constituency_urban)
drop _merge

* Merge with election results - 2019
merge 1:1 teryt_gminy polling_station_no2019 using "Data\Elections\results_sejm2019.dta"
drop if _merge == 2
drop _merge

drop if abs(dist_to_treated_boundary2019) > 30 & abs(dist_to_ukr_placebo_boundary) > 30

* Gen vars for 2015
gen turnout2015 = ballots2015/voters2015
gen nonregistered_share2015 = nonregistered_voters2015/ballots2015
gen vote_share_psl2015 = votes_psl2015/votes_valid2015
gen vote_share_pis2015 = votes_pis2015/votes_valid2015
gen vote_share_po2015 = votes_po2015/votes_valid2015
gen vote_share_now2015 = votes_now2015/votes_valid2015
gen vote_share_kukiz2015 = votes_kukiz2015/votes_valid2015
gen vote_share_korwin2015 = votes_korwin2015/votes_valid2015
gen vote_share_braun2015 = votes_braun2015/votes_valid2015
gen vote_share_razem2015 = votes_razem2015/votes_valid2015
gen vote_share_lewica2015 = votes_lewica2015/votes_valid2015
gen vote_share_left_oppo2015 = vote_share_po2015 + vote_share_now2015 + vote_share_psl2015 + vote_share_razem2015 + vote_share_lewica2015
gen vote_share_right_oppo2015 =  vote_share_kukiz2015 + vote_share_korwin2015 + vote_share_braun2015

* Gen vars for 2019
gen turnout2019 = ballots2019/voters2019
gen nonregistered_share2019 = nonregistered_voters2019/ballots2019
gen vote_share_psl2019 = votes_psl2019/votes_valid2019
gen vote_share_pis2019 = votes_pis2019/votes_valid2019
gen vote_share_ko2019 = votes_ko2019/votes_valid2019
gen vote_share_sld2019 = votes_sld2019/votes_valid2019
gen vote_share_konfed2019 = votes_konfed2019/votes_valid2019
gen vote_share_left_oppo2019 = vote_share_ko2019 + vote_share_sld2019 + vote_share_psl2019
gen vote_share_right_oppo2019 = vote_share_konfed2019

* Predictions/ extrapolations
regress vote_share_pis2015 vote_share_pis2019 
predict pr_vote_share_pis2015, xb
replace vote_share_pis2015 = pr_vote_share_pis2015 if missing(vote_share_pis2015)

regress vote_share_left_oppo2015 vote_share_left_oppo2019
predict pr_vote_share_left_oppo2015, xb
replace vote_share_left_oppo2015 = pr_vote_share_left_oppo2015 if missing(vote_share_left_oppo2015)

regress vote_share_right_oppo2015 vote_share_right_oppo2019
predict pr_vote_share_right_oppo2015, xb
replace vote_share_right_oppo2015 = pr_vote_share_right_oppo2015 if missing(vote_share_right_oppo2015)

regress turnout2015 turnout2019
predict pr_turnout2015, xb
replace turnout2015 = pr_turnout2015 if missing(turnout2015)

regress population2015 population2019
predict pr_population2015, xb
replace population2015 = pr_population2015 if missing(population2015)

regress voters2015 voters2019 
predict pr_voters2015, xb
replace voters2015 = pr_voters2015 if missing(voters2015)

* Structure data as panel
reshape long vote_share_pis vote_share_left_oppo vote_share_right_oppo turnout voters nonregistered_share population, i(polling_station_id2019) j(Year) 
xtset polling_station_id2019 Year, delta(4)
sort polling_station_id2019 Year

gen diff_vote_share_pis = d.vote_share_pis 
gen diff_vote_share_left_oppo = d.vote_share_left_oppo 
gen diff_vote_share_right_oppo = d.vote_share_right_oppo 
gen diff_turnout = d.turnout

* Labels
label var turnout "Turnout"
label var population "Population Within Polling Station's Catchment Area"
label var voters "Registered Voters Within Polling Station's Catchment Area"
label var Year "Year"
label var ballots2015 "Number of Ballots Issued to Voters in 2015"
label var nonregistered_voters2015 "Number of Voters Voting Based on an Attestation in 2015"
label var votes_valid2015 "Number of Valid Votes in 2015"
label var votes_pis2015 "Votes for PIS in 2015"
label var votes_po2015 "Votes for PLATFORMA OBYWATELSKA in 2015"
label var votes_razem2015 "Votes for RAZEM in 2015"
label var votes_korwin2015 "Votes for KORWIN in 2015"
label var votes_psl2015 "Votes for PSL in 2015"
label var votes_lewica2015 "Votes for ZJEDNOCZONA LEWICA in 2015"
label var votes_kukiz2015 "Votes for KUKIZ in 2015"
label var votes_now2015 "Votes for NOWOCZESNA in 2015"
label var votes_jow2015 "Votes for JOW BEZPARTYJNI in 2015"
label var votes_stonoga2015 "Votes for STONOGA in 2015"
label var votes_ruchspol2015 "Votes for RUCH SPOŁECZNY RP in 2015"
label var votes_zjedsla2015 "Votes for ZJEDNOCZENI DLA ŚLĄSKA in 2015"
label var votes_so2015 "Votes for SAMOOBRONA in 2015"
label var votes_braun2015 "Votes for BRAUN - SZCZĘŚĆ BOŻE in 2015"
label var votes_knp2015 "Votes for KONGRES NOWEJ PRAWICY in 2015"
label var votes_mn2015 "Votes for MNIEJSZOŚĆ NIEMIECKA in 2015"
label var votes_obyw2015 "Votes for OBYWATELE DO PARLAMENTU in 2015"
label var vote_share_psl2015 "PSL Vote Share in 2015"
label var vote_share_po2015 "PLATFORMA OBYWATELSKA Vote Share in 2015"
label var vote_share_now2015 "NOWOCZESNA Vote Share in 2015"
label var vote_share_kukiz2015 "KUKIZ Vote Share in 2015"
label var vote_share_korwin2015 "KORWIN Vote Share in 2015"
label var vote_share_braun2015 "BRAUN - SZCZĘŚĆ BOŻE Vote Share in 2015"
label var vote_share_razem2015 "RAZEM Vote Share in 2015"
label var vote_share_lewica2015 "LEWICA Vote Share in 2015"
label var nonregistered_share "Non-Resident Voter Share"
label var vote_share_psl2019 "PSL Vote Share in 2019"
label var vote_share_pis "PiS Vote Share in 2019"
label var vote_share_ko2019 "KOALICJA OBYWATELSKA Vote Share in 2019"
label var vote_share_sld2019 "SLD Vote Share in 2019"
label var vote_share_konfed2019 "KONFEDERACJA Vote Share in 2019"
label var pr_vote_share_pis2015 "Predicted PiS Vote Share in 2015"
label var pr_vote_share_left_oppo2015 "Predicted Left Opposition Vote Share in 2015"
label var pr_vote_share_right_oppo2015 "Predicted Right Opposition Vote Share in 2015"
label var pr_turnout2015 "Predicted Turnout in 2015"
label var pr_population2015 "Predicted Population Within Polling Station's Catchment Area in 2015"
label var pr_voters2015 "Predicted Registered Voters Within Polling Station's Catchment Area in 2015"
label var diff_vote_share_pis "Change in PiS Vote Share"
label var diff_vote_share_left_oppo "Change in Left Opposition Vote Share"
label var diff_vote_share_right_oppo "Change in Right Opposition Vote Share"
label var diff_turnout "Change in Turnout"
label var vote_share_left_oppo "Left Opposition Vote Share"
label var vote_share_right_oppo "Right Opposition Vote Share"


*****************************************************************************
**#                       2021 COMMUTERS DATAFRAME                        ***
*****************************************************************************

frames change commuters2021

import excel "Data\Commuters\commuter_flows_matrix.xlsx", sheet("Macierz przepływów") firstrow clear

* Prepare data

** Clean up
drop spistreści
rename KodgminyzamieszkaniaGminaof teryt_origin
rename NazwagminyzamieszkaniaGminao gmina_origin
rename KodgminypracyGminaoflabour teryt_destination
rename NazwagminypracyGminaoflabou gmina_destination
rename DojeżdżającyCommuters commuters

gen teryt_origin6 = substr(teryt_origin, 1, 6)
gen teryt_destination6 = substr(teryt_destination, 1, 6)

** Code municipalities (gminas) as part of the sample or not
gen origin_in_sample = 0
replace origin_in_sample = 1 if teryt_origin6 == "060102" | teryt_origin6 == "060103" | teryt_origin6 == "060104" | teryt_origin6 == "060105" | teryt_origin6 == "060106" | teryt_origin6 == "060107" | teryt_origin6 == "060108" | teryt_origin6 == "060109" | teryt_origin6 == "060110" | teryt_origin6 == "060111" | teryt_origin6 == "060112" | teryt_origin6 == "060113" | teryt_origin6 == "060114" | teryt_origin6 == "060115" | teryt_origin6 == "060116" | teryt_origin6 == "060117" | teryt_origin6 == "060118" | teryt_origin6 == "060119" | teryt_origin6 == "060303" | teryt_origin6 == "060304" | teryt_origin6 == "060309" | teryt_origin6 == "060310" | teryt_origin6 == "060312" | teryt_origin6 == "061001" | teryt_origin6 == "061301" | teryt_origin6 == "061302" | teryt_origin6 == "061305" | teryt_origin6 == "061307" | teryt_origin6 == "061901" | teryt_origin6 == "061902" | teryt_origin6 == "061903" | teryt_origin6 == "061904" | teryt_origin6 == "061905" | teryt_origin6 == "061906" | teryt_origin6 == "061907" | teryt_origin6 == "061908" | teryt_origin6 == "066101" | teryt_origin6 == "141001" | teryt_origin6 == "141002" | teryt_origin6 == "141003" | teryt_origin6 == "141004" | teryt_origin6 == "141005" | teryt_origin6 == "141006" | teryt_origin6 == "142602" | teryt_origin6 == "142607" | teryt_origin6 == "200101" | teryt_origin6 == "200102" | teryt_origin6 == "200104" | teryt_origin6 == "200105" | teryt_origin6 == "200106" | teryt_origin6 == "200107" | teryt_origin6 == "200202" | teryt_origin6 == "200204" | teryt_origin6 == "200207" | teryt_origin6 == "200209" | teryt_origin6 == "200213" | teryt_origin6 == "200214" | teryt_origin6 == "200301" | teryt_origin6 == "200303" | teryt_origin6 == "200304" | teryt_origin6 == "200306" | teryt_origin6 == "200501" | teryt_origin6 == "200502" | teryt_origin6 == "200503" | teryt_origin6 == "200504" | teryt_origin6 == "200505" | teryt_origin6 == "200506" | teryt_origin6 == "200507" | teryt_origin6 == "200508" | teryt_origin6 == "200509" | teryt_origin6 == "200901" | teryt_origin6 == "200902" | teryt_origin6 == "200903" | teryt_origin6 == "200904" | teryt_origin6 == "200905" | teryt_origin6 == "201001" | teryt_origin6 == "201003" | teryt_origin6 == "201005" | teryt_origin6 == "201006" | teryt_origin6 == "201007" | teryt_origin6 == "201009" | teryt_origin6 == "201101" | teryt_origin6 == "201102" | teryt_origin6 == "201103" | teryt_origin6 == "201104" | teryt_origin6 == "201105" | teryt_origin6 == "201106" | teryt_origin6 == "201107" | teryt_origin6 == "201108" | teryt_origin6 == "201109" | teryt_origin6 == "201110" | teryt_origin6 == "201207" | teryt_origin6 == "201208"
keep if origin_in_sample == 1 // focus only on municipalities that overlap with our sample
drop origin_in_sample

** Code origin muncipalities that are part of the treated area
gen origin_treated = 0
replace origin_treated = 1 if teryt_origin6 == "060102" | teryt_origin6 == "060105" | teryt_origin6 == "060106" | teryt_origin6 == "060107" | teryt_origin6 == "060112" | teryt_origin6 == "060114" | teryt_origin6 == "060116" | teryt_origin6 == "061901" | teryt_origin6 == "061902" | teryt_origin6 == "061906" | teryt_origin6 == "200207" | teryt_origin6 == "200502" | teryt_origin6 == "200503" | teryt_origin6 == "201007" | teryt_origin6 == "201104" | teryt_origin6 == "201105" | teryt_origin6 == "201106"
drop if origin_treated == 1 // remove commuter outflows from treated areas (focus on inflows)
drop origin_treated

** Code destination muncipalities that are part of the treated area
gen destination_treated = 0
replace destination_treated = 1 if teryt_destination6 == "060102" | teryt_destination6 == "060105" | teryt_destination6 == "060106" | teryt_destination6 == "060107" | teryt_destination6 == "060112" | teryt_destination6 == "060114" | teryt_destination6 == "060116" | teryt_destination6 == "061901" | teryt_destination6 == "061902" | teryt_destination6 == "061906" | teryt_destination6 == "200207" | teryt_destination6 == "200502" | teryt_destination6 == "200503" | teryt_destination6 == "201007" | teryt_destination6 == "201104" | teryt_destination6 == "201105" | teryt_destination6 == "201106"

gen commuters_to_state_of_emergency = 0
replace commuters_to_state_of_emergency = commuters if destination_treated == 1

** Sum up all communiters to various affected municipalities for each origin municipality
collapse (sum) commuters_to_state_of_emergency (first) gmina_origin, by(teryt_origin)

** Include population data
merge 1:1 teryt_origin using "Data\Commuters\population2021.dta"
drop if _merge == 2
drop _merge

** Generate a summary variable of the number of commuters commuting to the treated area municipalities per 1000 inhabitants
gen commuters_per_population = commuters_to_state_of_emergency / population

** Label vars
label var teryt_origin "TERYT Code of Origin Gmina"
label var commuters_to_state_of_emergency "Commuters to Treated Area - Number"
label var gmina_origin "Origin Gmina Name"
label var commuters_per_population "Treated Area Commuters to Population Ratio"

*****************************************************************************
**#                             END OF SET UP                             ***
*****************************************************************************

frames save "dataset", frames(_all) complevel(0) replace

*****************************************************************************
**#                             DATA ANALYSIS                             ***
*****************************************************************************

***********************************
**# Table 1: Comparison of Pre-treatment Means by Treatment Group
***********************************

frame change data2019

local vars population voters constituency_urban turnout vote_share_pis vote_share_left_oppo vote_share_right_oppo lat lon
local if "if abs(dist_to_treated_boundary)<30 & partial_treated == 0"

* Labels
label var vote_share_pis2019 "PiS Vote Share"
label var vote_share_left_oppo2019 "Left Opposition Vote Share"
label var vote_share_right_oppo2019 "Right Opposition Vote Share"
label var turnout2019 "Turnout"
label var population2019 "Population"
label var constituency_urban "Urban Constituency (Yes=1)"
label var voters2019 "Registered Voters"

* Generate no. of obs
tab treated `if', matcell(treatfreq)
matrix treatfreq=treatfreq\r(N)
local obs_con = treatfreq[1,1]
local obs_tre = treatfreq[2,1]

* Generate a simple covariate table
foreach var of varlist `vars' {
	** Run a regression for groups and Store the means for each group --- exclude partially treated
	reg `var' treated `if', robust
	global m`var'_0: di %10.2fc _b[_cons]
	global m`var'_1: di %10.2fc _b[_cons] + _b[treated]
	global dif_`var': di %10.2fc _b[treated]
	
	** Store the p-value 
	qui test treated=0
	global p_`var': di %12.2fc r(p)

	** Store the label of the variable
	global lbe_`var' : var label `var'
}

* Generating table
capture mkdir "Tables"

texdoc init "Tables/Table_1.tex", replace force
tex \begin{table}[htbp]\centering\small
tex \setlength\tabcolsep{0pt}
tex \caption{Summary of Pre-Treatment Means in 2019 by Treatment Status}
tex \label{table:summary:means}
tex \begin{tabularx}{1.0\hsize}{l *{4}{Y}}
tex \toprule
tex   &        Control  &      Treatment  & Difference & P-value \\
tex \cmidrule(lr){2-3} \cmidrule(lr){4-5}    &        N=`obs_con' &   N=`obs_tre'  &  &    \\
tex \midrule
foreach var of varlist `vars' {
	tex ${lbe_`var'} &  ${m`var'_0} & ${m`var'_1} & ${dif_`var'} & ${p_`var'} \\
}
tex \bottomrule
tex \multicolumn{5}{p{\linewidth}}{\scriptsize \emph{Notes}: Table reports mean variable values by group. Control group includes all untreated polling stations within 30 kilometers from the state of emergency boundary. Last column reports p-values from a t-test comparing variable means of treatment and control groups.}\\
tex \end{tabularx}
tex \end{table}
texdoc close

***********************************
***********************************
***********************************



***********************************
**# Footnote 14: Determining Optimal Polynomial Order (Results Ommited from Paper)
***********************************

frame change data2015_2019

* List of variables to iterate over
local variables diff_vote_share_pis diff_vote_share_left_oppo diff_vote_share_right_oppo diff_turnout

* Create folder and open file
capture mkdir "Supplementary Analyses"
file open polynomial_order using "Supplementary Analyses/Footnote_14.txt", write replace

* Loop for each polynomial order value
foreach p in 0 1 2 {
	
    ** Initialize macros
    local sum_amse_cl = 0
    local sum_amse_bc = 0
    local counter = 0

    ** Loop through each variable
    foreach var in `variables' {
        foreach h in 15 20 25 {
            qui rdmse `var' dist_to_treated_boundary2019, c(0) p(`p') h(`h') b(`h') kernel(uniform)
            local sum_amse_cl = `sum_amse_cl' + r(amse_cl)
            local sum_amse_bc = `sum_amse_bc' + r(amse_bc)
            local counter = `counter' + 1
        }
    }

    ** Calculate and display averages for this p across all variables
    local total_runs = `counter'
    local avg_amse_cl = `sum_amse_cl' / `total_runs'
    local avg_amse_bc = `sum_amse_bc' / `total_runs'
    display "Combined Average AMSE_CL for p=`p': " `avg_amse_cl'
    display "Combined Average AMSE_BC for p=`p': " `avg_amse_bc'
	file write polynomial_order %9s ("Combined Average AMSE_CL for p=`p': ") %11.8f (`avg_amse_cl') _n
	file write polynomial_order %9s ("Combined Average AMSE_BC for p=`p': ") %11.8f (`avg_amse_bc') _n
}

* Close file
file close polynomial_order

***********************************
***********************************
***********************************



***********************************
**# Figure 3 and Table A.3: Pre-Treatment Balance
***********************************

frame change data2015_2019

* Conduct randomization inference and generate confidence intervals

** Note: we utilize the Python implementation of rdrandinf because of the computationally-intensive nature of the task

python:
from sfi import Data
from sfi import Macro
import numpy as np
from rdlocrand import rdrandinf, rdwinselect
import pandas as pd

variable_names = ['diff_vote_share_pis', 'diff_turnout', 'diff_vote_share_left_oppo', 'diff_vote_share_right_oppo' , 'dist_to_treated_boundary2019', 'population', 'voters', 'constituency_urban', 'Year', 'partial_treated2019']

df = pd.DataFrame({var: Data.get(var) for var in variable_names})
df2 = df[(df['Year'] == 2019) & (df['partial_treated2019'] == 0)]

rd_vars = ['diff_vote_share_pis', 'diff_turnout', 'diff_vote_share_left_oppo', 'diff_vote_share_right_oppo' , 'population', 'voters', 'constituency_urban']
balance_covs = df2[['diff_vote_share_pis', 'diff_vote_share_left_oppo', 'diff_vote_share_right_oppo', 'diff_turnout']].to_numpy()
reps = int(Macro.getGlobal('reps'))

ci_vecs = {
    'diff_vote_share_pis': np.concatenate(([0.05], np.arange(-0.05, 0.05, 0.001))),
    'diff_vote_share_left_oppo': np.concatenate(([0.05], np.arange(-0.03, 0.06, 0.001))),
    'diff_vote_share_right_oppo': np.concatenate(([0.05], np.arange(-0.03, 0.025, 0.001))),
    'diff_turnout': np.concatenate(([0.05], np.arange(-0.03, 0.015, 0.001))),
    'population': np.concatenate(([0.05], np.arange(-250, 600, 10))),
    'voters': np.concatenate(([0.05], np.arange(-200, 500, 10))),
    'constituency_urban': np.concatenate(([0.05], np.arange(-0.23, 0.23, 0.001)))
}

for rd_var in rd_vars:
	
	ci_vec_current = ci_vecs[rd_var]
	
	out = rdrandinf(df2[rd_var], df2['dist_to_treated_boundary2019'], wl = -15, wr = 15, reps=reps, ci=ci_vec_current)
	
	Macro.setGlobal(f'l1_{rd_var}', str(out['obs.stat'][0]))
	Macro.setGlobal(f'p1_{rd_var}', str(out['p.value']))
	Macro.setGlobal(f'wl1_{rd_var}', str(out['window'][0]))
	Macro.setGlobal(f'wr1_{rd_var}', str(out['window'][1]))
	Macro.setGlobal(f'cil1_{rd_var}', str(out['ci'][0][0]))
	Macro.setGlobal(f'cir1_{rd_var}', str(out['ci'][0][1]))
	Macro.setGlobal(f'nl1_{rd_var}', str(out['sumstats'][1][0]))
	Macro.setGlobal(f'nr1_{rd_var}', str(out['sumstats'][1][1]))
	
	out = rdrandinf(df2[rd_var], df2['dist_to_treated_boundary2019'], wl = -20, wr = 20, reps=reps, ci=ci_vec_current)
	
	Macro.setGlobal(f'l2_{rd_var}', str(out['obs.stat'][0]))
	Macro.setGlobal(f'p2_{rd_var}', str(out['p.value']))
	Macro.setGlobal(f'wl2_{rd_var}', str(out['window'][0]))
	Macro.setGlobal(f'wr2_{rd_var}', str(out['window'][1]))
	Macro.setGlobal(f'cil2_{rd_var}', str(out['ci'][0][0]))
	Macro.setGlobal(f'cir2_{rd_var}', str(out['ci'][0][1]))
	Macro.setGlobal(f'nl2_{rd_var}', str(out['sumstats'][1][0]))
	Macro.setGlobal(f'nr2_{rd_var}', str(out['sumstats'][1][1]))	
	
	out = rdrandinf(df2[rd_var], df2['dist_to_treated_boundary2019'], wl = -25, wr = 25, reps=reps, ci=ci_vec_current)
	
	Macro.setGlobal(f'l3_{rd_var}', str(out['obs.stat'][0]))
	Macro.setGlobal(f'p3_{rd_var}', str(out['p.value']))
	Macro.setGlobal(f'wl3_{rd_var}', str(out['window'][0]))
	Macro.setGlobal(f'wr3_{rd_var}', str(out['window'][1]))
	Macro.setGlobal(f'cil3_{rd_var}', str(out['ci'][0][0]))
	Macro.setGlobal(f'cir3_{rd_var}', str(out['ci'][0][1]))
	Macro.setGlobal(f'nl3_{rd_var}', str(out['sumstats'][1][0]))
	Macro.setGlobal(f'nr3_{rd_var}', str(out['sumstats'][1][1]))	
	
	out = rdrandinf(df2[rd_var], df2['dist_to_treated_boundary2019'], reps=reps, ci = ci_vec_current, level = 0.15, nwindows = 20, wobs = 5, obsmin = 7, wasymmetric = True, covariates = balance_covs) 

	Macro.setGlobal(f'l4_{rd_var}', str(out['obs.stat'][0]))
	Macro.setGlobal(f'p4_{rd_var}', str(out['p.value']))
	Macro.setGlobal(f'wl4_{rd_var}', str(out['window'][0]))
	Macro.setGlobal(f'wr4_{rd_var}', str(out['window'][1]))
	Macro.setGlobal(f'cil4_{rd_var}', str(out['ci'][0][0]))
	Macro.setGlobal(f'cir4_{rd_var}', str(out['ci'][0][1]))
	Macro.setGlobal(f'nl4_{rd_var}', str(out['sumstats'][1][0]))
	Macro.setGlobal(f'nr4_{rd_var}', str(out['sumstats'][1][1]))	
	
	out = rdrandinf(df2[rd_var], df2['dist_to_treated_boundary2019'], wl = -5.50, wr = 3.49, reps=reps, ci=ci_vec_current)

	Macro.setGlobal(f'l5_{rd_var}', str(out['obs.stat'][0]))
	Macro.setGlobal(f'p5_{rd_var}', str(out['p.value']))
	Macro.setGlobal(f'wl5_{rd_var}', str(out['window'][0]))
	Macro.setGlobal(f'wr5_{rd_var}', str(out['window'][1]))
	Macro.setGlobal(f'cil5_{rd_var}', str(out['ci'][0][0]))
	Macro.setGlobal(f'cir5_{rd_var}', str(out['ci'][0][1]))
	Macro.setGlobal(f'nl5_{rd_var}', str(out['sumstats'][1][0]))
	Macro.setGlobal(f'nr5_{rd_var}', str(out['sumstats'][1][1]))	

end

* Define labels
label var diff_vote_share_pis "`=ustrunescape("\u0394")' PiS Vote Share (2015-2019)"
label var diff_vote_share_left_oppo "`=ustrunescape("\u0394")' Left Opp. Vote Share (2015-2019)"
label var diff_vote_share_right_oppo "`=ustrunescape("\u0394")' Right Opp. Vote Share (2015-2019)"
label var diff_turnout "`=ustrunescape("\u0394")' Turnout (2015-2019)"
label var population "Population (2019)"
label var voters "Registered Voters (2019)"
label var constituency_urban "Urban Constituency (Yes=1) (2019)"

* Generate figure
grstyle init
grstyle set plain, nogrid
graph set window fontface "LM Roman 10"

local rd_vars diff_vote_share_pis diff_turnout diff_vote_share_left_oppo diff_vote_share_right_oppo
local xaxis_ranges ""diff_vote_share_pis -0.10 0.10", "diff_vote_share_left_oppo -0.10 0.10", "diff_vote_share_right_oppo -0.10 0.10", "diff_turnout -0.10 0.10""
local count = 1
foreach var of varlist `rd_vars' {
    ** Initialize matrices for this variable's coefficients and CIs
    matrix coef_`var' = J(1,4,.)
    matrix CI_`var' = J(2,4,.)   
    
    ** Fill matrices with values from global macros and define window labels
    local i = 1
	local window_labels ""
    foreach model of numlist 1/4 {
        matrix coef_`var'[1, `i'] = ${l`model'_`var'}
        matrix CI_`var'[1, `i'] = ${cil`model'_`var'}
        matrix CI_`var'[2, `i'] = ${cir`model'_`var'}
		
        *** Retrieve the window size values + round
        local wl = round(${wl`i'_`var'}, 0.01)
        local wr = round(${wr`i'_`var'}, 0.01)
        
		*** Extract x-range
		foreach pair in `xaxis_ranges' {
			if ("`var'" == word("`pair'", 1)) {
				local xrange_lower = word("`pair'", 2)
				local xrange_upper = word("`pair'", 3)
				break
			}
		}
		
		*** Define x-tick interval
		local tick_interval = (`xrange_upper' - `xrange_lower') / 4
		
		*** Define labels
		local model_label "[`wl', `wr']"
        local ylabel_content "`ylabel_content' `i' "`model_label'""
        local ++i
    }

    ** Plot the LATE estimates with confidence intervals for this variable
    coefplot matrix(coef_`var'), ci(CI_`var') ///
             plotregion(style(none)) graphregion(style(none)) ///
             xline(0, lcolor(gs7) lpattern(dash)) ///
             ylabel(`ylabel_content', labsize(huge)) ///
			 xscale(range(`xrange_lower' `xrange_upper')) xlabel(`xrange_lower'(`tick_interval')`xrange_upper', labsize(huge)) ///
		 	 ciopts(lwidth(*5) lcolor(*.5)) ///
             name(panel_`var', replace)

    local ++count
    local window_labels "" 
	local ylabel_content ""
}

* Export coeffiicient plots as .jpg
capture mkdir "Figures"
graph export "Figures\Figure_3_a.jpg", as(jpg) name("panel_diff_vote_share_pis") fontface("LM Roman 10") replace
graph export "Figures\Figure_3_b.jpg", as(jpg) name("panel_diff_turnout") fontface("LM Roman 10") replace
graph export "Figures\Figure_3_c.jpg", as(jpg) name("panel_diff_vote_share_left_oppo") fontface("LM Roman 10") replace
graph export "Figures\Figure_3_d.jpg", as(jpg) name("panel_diff_vote_share_right_oppo") fontface("LM Roman 10") replace

* Re-Define labels
label var diff_vote_share_pis "$\Delta$ PiS Vote Share (2015-2019)"
label var diff_vote_share_left_oppo "$\Delta$ Left Opposition Vote Share (2015-2019)"
label var diff_vote_share_right_oppo "$\Delta$ Right Opposition Vote Share (2015-2019)"
label var diff_turnout "$\Delta$ Turnout (2015-2019)"
label var population "Population (2019)"
label var voters "Registered Voters (2019)"
label var constituency_urban "Urban Constituency (Yes=1) (2019)"

* Generating table
capture mkdir "Tables"
local vars diff_vote_share_pis diff_vote_share_left_oppo diff_vote_share_right_oppo diff_turnout population voters constituency_urban
local ascii_code 65
local wl4_diff_vote_share_pis: di %9.2f $wl4_diff_vote_share_pis
local wr4_diff_vote_share_pis: di %9.2f $wr4_diff_vote_share_pis
local wl5_diff_vote_share_pis: di %9.2f $wl5_diff_vote_share_pis
local wr5_diff_vote_share_pis: di %9.2f $wr5_diff_vote_share_pis
texdoc init "Tables/Table_A3.tex", replace force
tex \begin{table}[htbp]
tex \small
tex \caption{Pre-treatment Balance Test}
tex \vspace{-15pt}
tex \label{table:pretreatment:balance:test}
tex \begin{tabularx}{\textwidth}{l *{5}{Y}}
tex \toprule
tex & \multicolumn{3}{c}{Manual Windows} & \multicolumn{2}{c}{Data-driven} \\
tex \cmidrule(lr){5-6} &  & &  & (2015-19) & (2019-23) \\
tex \cmidrule(lr){2-4} \cmidrule(lr){5-6}
tex & \([$wl1_diff_vote_share_pis, $wr1_diff_vote_share_pis]\) & \([$wl2_diff_vote_share_pis, $wr2_diff_vote_share_pis]\) & \([$wl3_diff_vote_share_pis, $wr3_diff_vote_share_pis]\) & \([`wl4_diff_vote_share_pis',`wr4_diff_vote_share_pis']\) & \([`wl5_diff_vote_share_pis',`wr5_diff_vote_share_pis']\) \\
tex &  & &  & (registered) & (un-registered) \\
tex \midrule
foreach var of varlist `vars' {
	local panel_letter = char(`ascii_code')
	global lbe_`var' : var label `var'
	foreach v in l1 l2 l3 l4 l5 {
        local `v'_`var': di %9.3f ${`v'_`var'}
    }
	foreach v in cil1 cil2 cil3 cil4 cil5 cir1 cir2 cir3 cir4 cir5 {
		 if abs(${`v'_`var'}) < 1 {
			local `v'_`var': di %9.3f ${`v'_`var'}
		 }
		 else {
 	        local `v'_`var': di %9.3g ${`v'_`var'}
		 }
    }
    foreach v in p1 p2 p3 p4 p5 {
		local `v'_`var': di %9.2f ${`v'_`var'}
    }
	foreach v in nl1 nr1 nl2 nr2 nl3 nr3 nl4 nr4 nl5 nr5 {
		local `v'_`var': di %9.0f ${`v'_`var'}
    }
	tex \multicolumn{6}{l}{\textbf{Panel `panel_letter'. ${lbe_`var'}}} \\
	tex \midrule
    tex LATE & `l1_`var'' & `l2_`var'' & `l3_`var'' & `l4_`var'' & `l5_`var''\\
    tex P-value & `p1_`var'' & `p2_`var'' & `p3_`var'' & `p4_`var'' & `p5_`var'' \\
    tex 95\% CI & [`cil1_`var'', `cir1_`var''] & [`cil2_`var'', `cir2_`var''] & [`cil3_`var'', `cir3_`var''] & [`cil4_`var'', `cir4_`var''] & [`cil5_`var'', `cir5_`var''] \\
	tex \midrule
	local ++ascii_code
}
tex N treated &`nr1_diff_vote_share_pis' & `nr2_diff_vote_share_pis' & `nr3_diff_vote_share_pis' & `nr4_diff_vote_share_pis' & `nr5_diff_vote_share_pis' \\
tex N control & `nl1_diff_vote_share_pis' & `nl2_diff_vote_share_pis' & `nl3_diff_vote_share_pis' & `nl4_diff_vote_share_pis' & `nl5_diff_vote_share_pis' \\
tex \bottomrule
tex \multicolumn{6}{p{\linewidth}}{\scriptsize \emph{Notes}: Randomization-based inference results are obtained using the Python implementation of \emph{rdrandinf} by \citet{cattaneo_titiunik_vazquez_bare2016}. LATE point estimates reflect the unadjusted difference in means between treated and control observations using a uniform kernel. P-values and 95\% confidence intervals (estimated by inversion) are obtained through a Fisherian finite-sample exact randomization test of a sharp null hypothesis of no treatment effects based on 10,000 replications. Data-driven windows are selected using the \emph{rdwinselect} command by \citet{cattaneo_titiunik_vazquez_bare2016} and reflect the largest window around the cutoff such that the minimum p-value on the balance test across the four first-differenced outcome variables (in 2015-19 and 2019-23, respectively) is larger than 0.15. 2019-23 data-driven window was not pre-registered.}\\
tex \end{tabularx}
tex \end{table}
texdoc close

***********************************
***********************************
***********************************



***********************************
**# Section 4.3.3 - Commuter Flows into Treated Municipalities
***********************************

frame change commuters2021

* Summarize data

cap mkdir "Supplementary Analyses"
file open commuters_mean using "Supplementary Analyses/Section_4_3_3.txt", write replace

summarize commuters_per_population

file write commuters_mean "Summary Statistics for State of Emergency Commuters to Population Ratio:" _n
file write commuters_mean "Number of Observations (N)       = " %9.0f (r(N)) _n
file write commuters_mean "Mean                             = " %9.3f (r(mean)) _n
file write commuters_mean "Standard Deviation (SD)          = " %9.3f (r(sd)) _n
file write commuters_mean "Minimum Value                    = " %9.3f (r(min)) _n
file write commuters_mean "Maximum Value                    = " %9.3f (r(max)) _n

file close commuters_mean

***********************************
***********************************
***********************************



***********************************
**# Figure 4, Figure 5 and Table B.1: Main Results + Mechanisms
***********************************

frame change data2019_2023

* Conduct randomization inference and generate confidence intervals

** Note: we utilize the Python implementation of rdrandinf because of the computationally-intensive nature of the task

python:
from sfi import Data
from sfi import Macro
from rdlocrand import rdrandinf, rdwinselect
import pandas as pd
import numpy as np

variable_names = ['diff_vote_share_pis', 'diff_turnout', 'diff_vote_share_left_oppo', 'diff_vote_share_right_oppo' , 'dist_to_treated_boundary2023', 'Year', 'partial_treated2019'] 

df = pd.DataFrame({var: Data.get(var) for var in variable_names})
df2 = df[(df['Year'] == 2023) & (df['partial_treated2019'] == 0)]

rd_vars = ['diff_vote_share_pis', 'diff_turnout', 'diff_vote_share_left_oppo', 'diff_vote_share_right_oppo']
balance_covs = df2[['diff_vote_share_pis', 'diff_vote_share_left_oppo', 'diff_vote_share_right_oppo', 'diff_turnout']].to_numpy()
reps = int(Macro.getGlobal('reps'))

ci_vecs = {
	'diff_vote_share_pis': np.concatenate(([0.05], np.arange(-0.5, 0.03, 0.001))),
    'diff_vote_share_left_oppo': np.concatenate(([0.05], np.arange(-0.025, 0.045, 0.001))),
	'diff_vote_share_right_oppo': np.concatenate(([0.05], np.arange(-0.025, 0.02, 0.001))),
	'diff_turnout': np.concatenate(([0.05], np.arange(-0.02, 0.025, 0.001)))
}

for rd_var in rd_vars:
    ci_vec_current = ci_vecs[rd_var]

    out = rdrandinf(df2[rd_var], df2['dist_to_treated_boundary2023'], wl=-15, wr=15, reps=reps, ci=ci_vec_current, interfci=0.05)
    Macro.setGlobal(f'l1_{rd_var}', str(out['obs.stat'][0]))
    Macro.setGlobal(f'p1_{rd_var}', str(out['p.value']))
    Macro.setGlobal(f'wl1_{rd_var}', str(out['window'][0]))
    Macro.setGlobal(f'wr1_{rd_var}', str(out['window'][1]))
    Macro.setGlobal(f'cil1_{rd_var}', str(out['ci'][0][0]))
    Macro.setGlobal(f'cir1_{rd_var}', str(out['ci'][0][1]))
    Macro.setGlobal(f'crl1_{rd_var}', str(out['interf.ci'][0]))
    Macro.setGlobal(f'crr1_{rd_var}', str(out['interf.ci'][1]))
    Macro.setGlobal(f'nl1_{rd_var}', str(out['sumstats'][1][0]))
    Macro.setGlobal(f'nr1_{rd_var}', str(out['sumstats'][1][1]))
	
    out = rdrandinf(df2[rd_var], df2['dist_to_treated_boundary2023'], wl=-20, wr=20, reps=reps, ci=ci_vec_current, interfci=0.05)

    Macro.setGlobal(f'l2_{rd_var}', str(out['obs.stat'][0]))
    Macro.setGlobal(f'p2_{rd_var}', str(out['p.value']))
    Macro.setGlobal(f'wl2_{rd_var}', str(out['window'][0]))
    Macro.setGlobal(f'wr2_{rd_var}', str(out['window'][1]))
    Macro.setGlobal(f'cil2_{rd_var}', str(out['ci'][0][0]))
    Macro.setGlobal(f'cir2_{rd_var}', str(out['ci'][0][1]))
    Macro.setGlobal(f'crl2_{rd_var}', str(out['interf.ci'][0]))
    Macro.setGlobal(f'crr2_{rd_var}', str(out['interf.ci'][1]))
    Macro.setGlobal(f'nl2_{rd_var}', str(out['sumstats'][1][0]))
    Macro.setGlobal(f'nr2_{rd_var}', str(out['sumstats'][1][1]))

    out = rdrandinf(df2[rd_var], df2['dist_to_treated_boundary2023'], wl=-25, wr=25, reps=reps, ci=ci_vec_current, interfci=0.05)

    Macro.setGlobal(f'l3_{rd_var}', str(out['obs.stat'][0]))
    Macro.setGlobal(f'p3_{rd_var}', str(out['p.value']))
    Macro.setGlobal(f'wl3_{rd_var}', str(out['window'][0]))
    Macro.setGlobal(f'wr3_{rd_var}', str(out['window'][1]))
    Macro.setGlobal(f'cil3_{rd_var}', str(out['ci'][0][0]))
    Macro.setGlobal(f'cir3_{rd_var}', str(out['ci'][0][1]))
    Macro.setGlobal(f'crl3_{rd_var}', str(out['interf.ci'][0]))
    Macro.setGlobal(f'crr3_{rd_var}', str(out['interf.ci'][1]))
    Macro.setGlobal(f'nl3_{rd_var}', str(out['sumstats'][1][0]))
    Macro.setGlobal(f'nr3_{rd_var}', str(out['sumstats'][1][1]))

    out = rdrandinf(df2[rd_var], df2['dist_to_treated_boundary2023'], reps=reps, ci=ci_vec_current, level=0.15,
                    nwindows=20, wobs=5, obsmin=7, wasymmetric=True, covariates=balance_covs, interfci=0.05)

    Macro.setGlobal(f'l4_{rd_var}', str(out['obs.stat'][0]))
    Macro.setGlobal(f'p4_{rd_var}', str(out['p.value']))
    Macro.setGlobal(f'wl4_{rd_var}', str(out['window'][0]))
    Macro.setGlobal(f'wr4_{rd_var}', str(out['window'][1]))
    Macro.setGlobal(f'cil4_{rd_var}', str(out['ci'][0][0]))
    Macro.setGlobal(f'cir4_{rd_var}', str(out['ci'][0][1]))
    Macro.setGlobal(f'crl4_{rd_var}', str(out['interf.ci'][0]))
    Macro.setGlobal(f'crr4_{rd_var}', str(out['interf.ci'][1]))
    Macro.setGlobal(f'nl4_{rd_var}', str(out['sumstats'][1][0]))
    Macro.setGlobal(f'nr4_{rd_var}', str(out['sumstats'][1][1]))
	
end

* Define labels
label var diff_vote_share_pis "`=ustrunescape("\u0394")' PiS Vote Share (2019-2023)"
label var diff_vote_share_left_oppo "`=ustrunescape("\u0394")' Left Opp. Vote Share (2019-2023)"
label var diff_vote_share_right_oppo "`=ustrunescape("\u0394")' Right Opp. Vote Share (2019-2023)"
label var diff_turnout "`=ustrunescape("\u0394")' Turnout (2019-2023)"

* Generate figure
grstyle init
grstyle set plain, nogrid
graph set window fontface "LM Roman 10"

* Plot main results 

** Initialize matrices for this variable's coefficients and CIs
matrix coef_diff_vote_share_pis = J(1,4,.)
matrix CI_diff_vote_share_pis = J(2,4,.)   

** Fill matrices with values from global macros and define window labels
local i = 1
local window_labels ""
foreach model of numlist 1/4 {
	matrix coef_diff_vote_share_pis[1, `i'] = ${l`model'_diff_vote_share_pis}
	matrix CI_diff_vote_share_pis[1, `i'] = ${cil`model'_diff_vote_share_pis}
	matrix CI_diff_vote_share_pis[2, `i'] = ${cir`model'_diff_vote_share_pis}
	
	*** Retrieve and round the window size values
	local wl = round(${wl`i'_diff_vote_share_pis}, 0.01)
	local wr = round(${wr`i'_diff_vote_share_pis}, 0.01)
	
	*** Define labels
	local model_label "[`wl', `wr']"
	local ylabel_content "`ylabel_content' `i' "`model_label'""
	local ++i
}

** Plot LATE estimates
coefplot matrix(coef_diff_vote_share_pis), ci(CI_diff_vote_share_pis) ///
		 plotregion(style(none)) graphregion(style(none)) ///
		 xline(0, lcolor(gs7) lpattern(dash)) ///
		 ylabel(`ylabel_content', labsize(large)) ///
		 xscale(range(-0.1 0.1)) xlabel(-0.1(0.05)0.1, labsize(large)) ///
		 name(figure_main_results, replace) ///
		 mlabel("{it:{&tau}} = " + string(@b,"%4.3f")) mlabcolor(none) ///
		 ciopts(lwidth(*5) lcolor(*.5)) addplot(scatter @at @ul, ms(i) mlabel(@mlbl) mlabcolor(black) mlabsize(medium))

* Plot mechanism results

** Matrices - initialization
local rd_vars diff_turnout diff_vote_share_left_oppo diff_vote_share_right_oppo
local count = 1
foreach var of varlist `rd_vars' {
    ** Initialize matrices for this variable's coefficients and CIs
    matrix coef_`var' = J(1,4,.)
    matrix CI_`var' = J(2,4,.)   
    ** Fill matrices with values from global macros
    local i = 1
    foreach model of numlist 1/4 {
        matrix coef_`var'[1, `i'] = ${l`model'_`var'}
        matrix CI_`var'[1, `i'] = ${cil`model'_`var'}
        matrix CI_`var'[2, `i'] = ${cir`model'_`var'}
        local ++i
    }
}

** Coefficient matrices
matrix coef_a = (coef_diff_vote_share_left_oppo[1,1], coef_diff_vote_share_right_oppo[1,1], coef_diff_turnout[1,1]) // [-15, 15]
matrix coef_b = (coef_diff_vote_share_left_oppo[1,2], coef_diff_vote_share_right_oppo[1,2], coef_diff_turnout[1,2]) // [-20, 20]
matrix coef_c = (coef_diff_vote_share_left_oppo[1,3], coef_diff_vote_share_right_oppo[1,3], coef_diff_turnout[1,3]) // [-25, 25]
matrix coef_d = (coef_diff_vote_share_left_oppo[1,4], coef_diff_vote_share_right_oppo[1,4], coef_diff_turnout[1,4]) // [Data-driven]

** Confidence interval matrices 
matrix ci_lower_a = (CI_diff_vote_share_left_oppo[1,1], CI_diff_vote_share_right_oppo[1,1], CI_diff_turnout[1,1])
matrix ci_upper_a = (CI_diff_vote_share_left_oppo[2,1], CI_diff_vote_share_right_oppo[2,1], CI_diff_turnout[2,1])
matrix ci_lower_b = (CI_diff_vote_share_left_oppo[1,2], CI_diff_vote_share_right_oppo[1,2], CI_diff_turnout[1,2])
matrix ci_upper_b = (CI_diff_vote_share_left_oppo[2,2], CI_diff_vote_share_right_oppo[2,2], CI_diff_turnout[2,2])
matrix ci_lower_c = (CI_diff_vote_share_left_oppo[1,3], CI_diff_vote_share_right_oppo[1,3], CI_diff_turnout[1,3])
matrix ci_upper_c = (CI_diff_vote_share_left_oppo[2,3], CI_diff_vote_share_right_oppo[2,3], CI_diff_turnout[2,3])
matrix ci_lower_d = (CI_diff_vote_share_left_oppo[1,4], CI_diff_vote_share_right_oppo[1,4], CI_diff_turnout[1,4])
matrix ci_upper_d = (CI_diff_vote_share_left_oppo[2,4], CI_diff_vote_share_right_oppo[2,4], CI_diff_turnout[2,4])

** Plot LATE estimates
coefplot ///
    (matrix(coef_a), ci((ci_lower_a ci_upper_a)) mcolor(blue) msymbol(O) color(blue)) ///
    (matrix(coef_b), ci((ci_lower_b ci_upper_b)) mcolor(red) msymbol(D) color(red)) ///
    (matrix(coef_c), ci((ci_lower_c ci_upper_c)) mcolor(green) msymbol(T) color(green)) ///
    (matrix(coef_d), ci((ci_lower_d ci_upper_d)) mcolor(orange) msymbol(S) color(orange)), ///
    bylabel(r) legend(label(2 "[-15, 15]") label(4 "[-20, 20]") label(6 "[-25, 25]") label(8 "[-5.5, 3.49]") size(medlarge) pos(3) rows(4)) ///
    xline(0, lcolor(gs7) lpattern(dash)) /// 
	xscale(range(-0.1 0.1)) xlabel(-0.1(0.05)0.1, grid labsize(large)) ///
    plotregion(style(none)) graphregion(style(none)) ylabel(1 `" "`=ustrunescape("\u0394")' Left Opp." "Vote Share" "(2019-2023)" "' 2 `" "`=ustrunescape("\u0394")' Right Opp." "Vote Share" "(2019-2023)" "' 3 `" "`=ustrunescape("\u0394")' Turnout" "(2019-2023)" "', labsize(med) angle(vertical) ) ///
	mlabel("{it:{&tau}} = " + string(@b,"%4.3f")) mlabcolor(none) ///
	ciopts(lwidth(*5) lcolor(*.5)) addplot(scatter @at @ul, ms(i) mlabel(@mlbl) mlabcolor(black) mlabsize(medium)) ///
	name(figure_mechanisms, replace) 
	

* Export coeffiicient plots as .jpg
capture mkdir "Figures"
graph export "Figures\Figure_4.jpg", as(jpg) name("figure_main_results") fontface("LM Roman 10") replace
graph export "Figures\Figure_5.jpg", as(jpg) name("figure_mechanisms") fontface("LM Roman 10") replace

* Re-Define labels
label var diff_vote_share_pis "$\Delta$ PiS Vote Share (2019-2023)"
label var diff_vote_share_left_oppo "$\Delta$ Left Opposition Vote Share (2019-2023)"
label var diff_vote_share_right_oppo "$\Delta$ Right Opposition Vote Share (2019-2023)"
label var diff_turnout "$\Delta$ Turnout (2019-2023)"

* Generating table
capture mkdir "Tables"
local vars diff_vote_share_pis diff_vote_share_left_oppo diff_vote_share_right_oppo diff_turnout
local ascii_code 65
local wl4_diff_vote_share_pis: di %9.2f $wl4_diff_vote_share_pis
local wr4_diff_vote_share_pis: di %9.2f $wr4_diff_vote_share_pis
texdoc init "Tables/Table_B1.tex", replace force
tex \begin{table}[h!]
tex \small
tex \caption{Main Results}
tex \vspace{-15pt}
tex \label{table:main:results}
tex \begin{tabularx}{\textwidth}{l *{4}{Y}}
tex \toprule
tex & \multicolumn{3}{c}{Manual Windows} & \multicolumn{1}{c}{Data-driven} \\
tex \cmidrule(lr){2-4} \cmidrule(lr){5-5}
tex & \([$wl1_diff_vote_share_pis, $wr1_diff_vote_share_pis]\) & \([$wl2_diff_vote_share_pis, $wr2_diff_vote_share_pis]\) & \([$wl3_diff_vote_share_pis, $wr3_diff_vote_share_pis]\) & \([`wl4_diff_vote_share_pis',`wr4_diff_vote_share_pis']\) \\
tex \midrule
foreach var of varlist `vars' {
	local panel_letter = char(`ascii_code')
	global lbe_`var' : var label `var'
	foreach v in l1 l2 l3 l4 cil1 cil2 cil3 cil4 cir1 cir2 cir3 cir4 crl1 crl2 crl3 crl4 crr1 crr2 crr3 crr4 {
        local `v'_`var': di %9.3f ${`v'_`var'}
    }
    foreach v in p1 p2 p3 p4 {
		local `v'_`var': di %9.2f ${`v'_`var'}
    }
	foreach v in nl1 nr1 nl2 nr2 nl3 nr3 nl4 nr4 {
		local `v'_`var': di %9.0f ${`v'_`var'}
    }
	tex \multicolumn{5}{l}{\textbf{Panel `panel_letter'. ${lbe_`var'}}} \\
	tex \midrule
    tex LATE & `l1_`var'' & `l2_`var'' & `l3_`var'' & `l4_`var'' \\
    tex P-value & `p1_`var'' & `p2_`var'' & `p3_`var'' & `p4_`var'' \\
    tex 95\% CI & [`cil1_`var'', `cir1_`var''] & [`cil2_`var'', `cir2_`var''] & [`cil3_`var'', `cir3_`var''] & [`cil4_`var'', `cir4_`var''] \\
    tex Rosenbaum 95\% CI & [`crl1_`var'', `crr1_`var''] & [`crl2_`var'', `crr2_`var''] & [`crl3_`var'', `crr3_`var''] & [`crl4_`var'', `crr4_`var''] \\

	tex \midrule
	local ++ascii_code
}
tex N treated &`nr1_diff_vote_share_pis' & `nr2_diff_vote_share_pis' & `nr3_diff_vote_share_pis' & `nr4_diff_vote_share_pis' \\
tex N control & `nl1_diff_vote_share_pis' & `nl2_diff_vote_share_pis' & `nl3_diff_vote_share_pis' & `nl4_diff_vote_share_pis' \\
tex \bottomrule
tex \multicolumn{5}{p{\linewidth}}{\footnotesize \emph{Notes}: Table presents main estimation results. Randomization-based inference results are obtained using the Python implementation of \emph{rdrandinf} by \citet{cattaneo_titiunik_vazquez_bare2016}. LATE point estimates reflect the unadjusted difference in means between treated and control observations using a uniform kernel. P-values and 95\% confidence intervals (estimated by inversion) are obtained through a Fisherian finite-sample exact randomization test of a sharp null hypothesis of no treatment effects based on 10,000 replications. Rosenbaum 95\% CI refers to \citet{rosenbaum2007} bounds under interference. Data-driven window is selected using the \emph{rdwinselect} command by \citet{cattaneo_titiunik_vazquez_bare2016} and reflects the largest window around the cutoff such that the minimum p-value on the balance test across the four first-differenced outcome variables is larger than 0.15.}\\
tex \end{tabularx}
tex \end{table}
texdoc close

***********************************
***********************************
***********************************



*************************************************************************************
**# Table A.1 - Summary Statistics 
*************************************************************************************

frame change data2019_2023

label var treated2019 "Treated (Yes=1)"
label var dist_to_treated_boundary2023 "Dist. to Treatment Boundary (km)"
label var diff_vote_share_pis "$\Delta$ PiS Vote Share (2019-23)"
label var diff_vote_share_left_oppo "$\Delta$ Left Opp. Vote Share (2019-23)"
label var diff_vote_share_right_oppo "$\Delta$ Right Opp. Vote Share (2019-23)"
label var diff_turnout "$\Delta$ Turnout (2019-23)"
label var diff_nonreg_share "$\Delta$ Non-Res. Voter Share (2019-23)"
label var vote_share_pis "PiS Vote Share (2023)"
label var vote_share_left_oppo "Left Opp. Vote Share (2023)"
label var vote_share_right_oppo "Right Opp. Vote Share (2023)"
label var turnout "Turnout (2023)"
label var nonregistered_share "Non-Resident Voter Share (2023)"
label var voters "Registered Voters (2023)"
label var population "Population (2023)"
label var constituency_urban "Urban Constituency (Yes=1)"
label var parl_district6 "\hspace{3mm} Electoral District 6"
label var parl_district7 "\hspace{3mm} Electoral District 7"
label var parl_district18 "\hspace{3mm} Electoral District 18"
label var parl_district22 "\hspace{3mm} Electoral District 22"
label var parl_district23 "\hspace{3mm} Electoral District 23"
label var parl_district24 "\hspace{3mm} Electoral District 24"

estpost tabstat treated2019 dist_to_treated_boundary2023 constituency_urban parl_district6 parl_district7 parl_district18 parl_district24 population voters vote_share_pis vote_share_left_oppo vote_share_right_oppo turnout nonregistered_share diff_vote_share_pis diff_vote_share_left_oppo diff_vote_share_right_oppo diff_turnout diff_nonreg_share if Year == 2023 & abs(dist_to_treated_boundary2023) <= 30 & partial_treated2019 == 0 , statistics(mean sd min p25 p50 p75 max count) columns(statistics) 

capture mkdir "Tables"

esttab . using "Tables/Table_A1.tex", cells("mean(fmt(a2) label(Mean)) sd(fmt(a2) label(Std.\ Dev.)) min(fmt(a2) label(Min.)) p25(fmt(a1) label(25\%)) p50(fmt(a1) label(50\%)) p75(fmt(a1) label(75\%)) max(fmt(a2) label(Max.)) count(fmt(a2) label(N))") nostar nonumbers nomtitle label booktabs replace noobs refcat(parl_district6 "\emph{Electoral District}", nolabel) prehead(`"{\footnotesize"' `"\begin{xltabular}{\linewidth}{l *{8}{Y} @{}}"' `"\caption{@title}"' `"\label{table:summary:statistics}\\"' `"\toprule"') posthead(`"\midrule"' `"\endfirsthead"' `"\toprule"' `"  & Mean  & Std.\ Dev.& Min.& 25\%& 50\%& 75\%& Max.& N\\"' `"\midrule"' `"\endhead"' `"\midrule\multicolumn{9}{r}{\itshape continues on next page}\\\midrule\endfoot"' `"\bottomrule\endlastfoot"')  postfoot( )  title("Table of Summary Statistics")  noisily

label var vote_share_pis "PiS Vote Share (2019)"
label var vote_share_left_oppo "Left Opp. Vote Share (2019)"
label var vote_share_right_oppo "Right Opp. Vote Share (2019)"
label var turnout "Turnout (2019)"
label var nonregistered_share "Non-Resident Voter Share (2019)"
label var voters "Registered Voters (2019)"
label var population "Population (2019)"

estpost tabstat population voters vote_share_pis vote_share_left_oppo vote_share_right_oppo turnout nonregistered_share if Year == 2019 & abs(dist_to_treated_boundary2023) <= 30 & partial_treated2019 == 0 , statistics(mean sd min p25 p50 p75 max count) columns(statistics) 

esttab . using "Tables/Table_A1.tex", cells("mean(fmt(a2)) sd(fmt(a2)) min(fmt(a2)) p25(fmt(a1)) p50(fmt(a1)) p75(fmt(a1)) max(fmt(a2)) count(fmt(a2))") nostar nonumbers nomtitles nodepvars label booktabs append noobs prehead( ) posthead( )  eqlabels(, begin(" " "") nofirst) collabels(none) nonumbers postfoot( )

frame change data2015_2019

label var diff_vote_share_pis "$\Delta$ PiS Vote Share (2015-19)"
label var diff_vote_share_left_oppo "$\Delta$ Left Opp. Vote Share (2015-19)"
label var diff_vote_share_right_oppo "$\Delta$ Right Opp. Vote Share (2015-19)"
label var diff_turnout "$\Delta$ Turnout (2015-19)"

estpost tabstat diff_vote_share_pis diff_vote_share_left_oppo diff_vote_share_right_oppo diff_turnout  if Year == 2019 & abs(dist_to_treated_boundary2019) <= 30 & partial_treated2019 == 0 , statistics(mean sd min p25 p50 p75 max count) columns(statistics) 

esttab . using "Tables/Table_A1.tex", cells("mean(fmt(a2) label(Mean)) sd(fmt(a2) label(Std.\ Dev.)) min(fmt(a2) label(Min.)) p25(fmt(a1) label(25\%)) p50(fmt(a1) label(50\%)) p75(fmt(a1) label(75\%)) max(fmt(a2) label(Max.)) count(fmt(a2) label(N))") nostar nonumbers nomtitle label booktabs append noobs prehead( ) posthead( )  eqlabels(, begin(" " "") nofirst) collabels(none) nonumbers postfoot(`"\bottomrule"' `"\multicolumn{@span}{p{\linewidth}}{\scriptsize \emph{Notes}: Table reports summary statistics for our main sample and includes all polling stations within 30 kilometers from the state of emergency boundary.}\\"' `"\end{xltabular}"' `"}"') 

*************************************************************************************
*************************************************************************************
*************************************************************************************



***********************************
**# Figure A.1: Scatter Plots of Pre-Treatment Covariates
***********************************

frame change data2015_2019

*** Generate individual figures
capture graph set window fontface "LM Roman 10"

preserve

label var vote_share_pis "PiS Vote Share 2019"
label var vote_share_left_oppo "Left Opp. Vote Share 2019"
label var vote_share_right_oppo "Right Opp. Vote Share 2019"
label var turnout "Turnout 2019"

label var diff_vote_share_pis "`=ustrunescape("\u0394")' PiS Vote Share 2015-19"
label var diff_vote_share_left_oppo "`=ustrunescape("\u0394")' Left Opp. Vote Share 2015-19"
label var diff_vote_share_right_oppo "`=ustrunescape("\u0394")' Right Opp. Vote Share 2015-19"
label var diff_turnout "`=ustrunescape("\u0394")' Turnout 2015-2019"

keep if Year == 2019
keep if partial_treated2019 == 0

foreach outcome_var of varlist vote_share_pis turnout vote_share_left_oppo vote_share_right_oppo diff_vote_share_pis diff_turnout diff_vote_share_left_oppo diff_vote_share_right_oppo {
	local running_var = "dist_to_treated_boundary"
	local min = -20
	local max = 3.5
	local outcome_label : variable label `outcome_var'
	* Calculate the means for the two groups
	qui summarize `outcome_var' if `running_var' < 0 & `running_var' > `min'
	local mean_left = r(mean)
	qui summarize `outcome_var' if `running_var' > 0 & `running_var' < `max'
	local mean_right = r(mean)
	* Plot
	twoway  (scatter `outcome_var' `running_var' if `running_var' > `min' & `running_var' < 0, mcolor("135 206 250%50") msize(small) mlwidth(vthin)) ///
    (scatter `outcome_var' `running_var' if `running_var' >= 0 & `running_var' < `max', mcolor("240 122 136%50") msize(small) mlwidth(vthin)) ///
    (function y = `mean_left', range(`min' 0) lcolor(navy) lpattern(solid) lwidth(medium)) ///
    (function y = `mean_right', range(0 `max') lcolor(maroon) lpattern(solid) lwidth(medium)), ///
    xline(0, lcolor(black) lwidth(thin) lpattern(dash)) ///
    legend(off) ///
    title("", size(large)) ///
    ylabel(, format(%9.2f) labsize(medium) nogrid) xlabel(, labsize(medium) nogrid) xtick(`min' 0 `max') ///
    ytitle("`outcome_label'", margin(small) size(medium)) xtitle("Distance to treatment boundary (km)", margin(small) size(medium)) ///
    xscale(range(`min' `max')) ///
    graphregion(color(white))  ///
    name(graph_`outcome_var', replace)
}

restore

graph combine graph_vote_share_pis graph_turnout graph_vote_share_left_oppo graph_vote_share_right_oppo, name(scatter_combined1, replace) cols(2)
graph combine graph_diff_vote_share_pis graph_diff_turnout graph_diff_vote_share_left_oppo graph_diff_vote_share_right_oppo, name(scatter_combined2, replace) cols(2)

capture mkdir "Figures"
//graph export "Figures\Figure_A1_a.pdf", as(pdf) name("scatter_combined1") fontface("LM Roman 10") replace
//graph export "Figures\Figure_A1_b.pdf", as(pdf) name("scatter_combined2") fontface("LM Roman 10") replace
graph export "Figures\Figure_A1_a.jpg", as(jpg) name("scatter_combined1") fontface("LM Roman 10") replace
graph export "Figures\Figure_A1_b.jpg", as(jpg) name("scatter_combined2") fontface("LM Roman 10") replace

***********************************
***********************************
***********************************



***********************************
**# Figure A.2: Pre-Treatment Balance Across Different Bandwidths
***********************************

frame change data2015_2019

* Generate individual figures
capture graph set window fontface "LM Roman 10"

rdwinselect dist_to_treated_boundary diff_vote_share_pis if partial_treated == 0, plot wasymm wmin(30) wstep(-1) nwindows(28) level(0.05) dropmissing graph_options(title(`=ustrunescape("\u0394")' PiS Vote Share) xtitle(Distance to treatment boundary (km)) ytitle(P-value) yscale(range(0 1)) ylabel(0(0.2)1) xscale(range(3 30)) xlabel(5(5)30) yline(0.05, lpattern(dot)) name(graph1, replace)) reps($reps)

rdwinselect dist_to_treated_boundary diff_turnout if partial_treated == 0, plot wasymm wmin(30) wstep(-1) nwindows(28) level(0.05) dropmissing graph_options(title(`=ustrunescape("\u0394")' Turnout) xtitle(Distance to treatment boundary (km)) ytitle(P-value) yscale(range(0 1)) ylabel(0(0.2)1) xscale(range(3 30)) xlabel(5(5)30) yline(0.05, lpattern(dot)) name(graph2, replace)) reps($reps)

rdwinselect dist_to_treated_boundary diff_vote_share_left_oppo if partial_treated == 0, plot wasymm wmin(30) wstep(-1) nwindows(28) level(0.05) dropmissing graph_options(title(`=ustrunescape("\u0394")' Left Opposition Vote Share) xtitle(Distance to treatment boundary (km)) ytitle(P-value) yscale(range(0 1)) ylabel(0(0.2)1) xscale(range(3 30)) xlabel(5(5)30) yline(0.05, lpattern(dot)) name(graph3, replace)) reps($reps)

rdwinselect dist_to_treated_boundary diff_vote_share_right_oppo if partial_treated == 0, plot wasymm wmin(30) wstep(-1) nwindows(28) level(0.05) dropmissing graph_options(title(`=ustrunescape("\u0394")' Right Opposition Vote Share) xtitle(Distance to treatment boundary (km)) ytitle(P-value) yscale(range(0 1)) ylabel(0(0.2)1) xscale(range(3 30)) xlabel(5(5)30) yline(0.05, lpattern(dot)) name(graph4, replace)) reps($reps)

* Combine and export figures
graph combine graph1 graph2 graph3 graph4, name(graph_combined, replace) cols(2) ysize(12) xsize(11)  imargin(medium) iscale(*.8) 
capture mkdir "Figures"
//graph export "Figures\Figure_A2.pdf", as(pdf) name("graph_combined") fontface("LM Roman 10") replace
graph export "Figures\Figure_A2.jpg", as(jpg) name("graph_combined") fontface("LM Roman 10") replace

***********************************
***********************************
***********************************



***********************************
*** Section A7: Power Analysis
***********************************

frame change data2015_2019

* Program to calculate Minimum Detectable Effects
program define find_mde, rclass
    syntax, dv(string) rv(string) tv(string) wl(real) wr(real) [if(string)] [power(real 0.8)] [alpha(real 0.05)]
	local pwl = `wl'
	local pwr = `wr'
	local palpha `alpha' 
	local ppower `power' 
	local pdv = "`dv'"
	local prv = "`rv'"
	local ptv = "`tv'"
	local pif = ""
	if "`if'" != "" {
		local pif "& `if'"
	} 
	qui reg `pdv' `ptv' if `prv' > `pwl' & `prv' < `pwr' `pif', vce(hc2)
	local se = _se[`ptv']
	** Calculate the z-scores
	local z_alpha invnormal(1-`palpha'/2)
	local z_beta invnormal(`ppower')
	** Calculate the MDE
	local mde = (`z_alpha' + `z_beta') * `se'
	** Display the MDE 
	display "MDE = " `mde'
	return scalar mde = `mde'	
end

* Create folder and open file
capture mkdir "Supplementary Analyses"
file open power_analysis using "Supplementary Analyses/Section_A7.txt", write replace

* Conduct power analysis
local dep_vars "diff_vote_share_pis diff_vote_share_left_oppo diff_vote_share_right_oppo diff_turnout"
foreach dep_var of local dep_vars {
	di "Power analysis for `dep_var':"
	file write power_analysis %9s ("Power analysis for `dep_var':") _n
	find_mde, dv(`dep_var') rv(dist_to_treated_boundary2019) tv(treated2019) if(partial_treated2019 == 0) wl(-4.39) wr(3.49)
	file write power_analysis "MDE for [-4.39, 3.49] = " %9.8f (r(mde)) _newline
	foreach bandwidth in 15 20 25 {
		find_mde, dv(`dep_var') rv(dist_to_treated_boundary2019) tv(treated2019) if(partial_treated2019 == 0) wl(-`bandwidth') wr(`bandwidth')
		file write power_analysis "MDE for [-`bandwidth', `bandwidth'] = " %9.8f (r(mde)) _newline
	}
	file write power_analysis _n
}

* Close file
file close power_analysis

***********************************
***********************************
***********************************



***********************************
**# Table B.2: Equivalence Testing
***********************************

frame change data2019_2023

** Randomization inference in Python
python:
from sfi import Data
from sfi import Macro
import pandas as pd
import numpy as np
import statsmodels.api as sm
import os

# Define functions

def regression_permutation_test(y, x, treatment_effect, reps=1000, seed=666, direction="two-sided"):
    np.random.seed(seed)
    X = sm.add_constant(x)
    y_adjusted = y - X.iloc[:, 1] * treatment_effect
    original_model = sm.OLS(y_adjusted, X).fit()
    T_obs = original_model.params.iloc[1]
    permuted_T = []
    for _ in range(reps):
        x_permuted = X.copy()
        x_permuted.iloc[:, 1] = np.random.permutation(x_permuted.iloc[:, 1])
        permuted_model = sm.OLS(y_adjusted, x_permuted).fit()
        T_perm = permuted_model.params.iloc[1]
        permuted_T.append(T_perm)
        if direction == "greater":
            p_value = np.mean([T >= T_obs for T in permuted_T])
        elif direction == "less":
            p_value = np.mean([T <= T_obs for T in permuted_T])
        else:
            p_value = np.mean([abs(T) >= abs(T_obs) for T in permuted_T])
    return p_value

def find_ci_equivalence(y, x, step=0.001, alpha=0.05, reps=1000, weights=None):
    ci_bounds = []
    effect_lower = -step
    effect_upper = step
    p_value = 1
    while p_value > alpha:
        p_value = regression_permutation_test(y, x, effect_upper, reps=reps, direction="less")
        #print(f"Effect upper: {effect_upper} , p-value: {p_value}")
        ci_bounds.append(effect_upper)
        effect_upper = effect_upper + step
    p_value = 1
    while p_value > alpha:
        p_value = regression_permutation_test(y, x, effect_lower, reps=reps, direction="greater")
        #print(f"Effect lower: {effect_lower} , p-value: {p_value}")
        ci_bounds.append(effect_lower)
        effect_lower = effect_lower - step
    return min(ci_bounds), max(ci_bounds)


def equivalence_test(y, x, equiv_bound, reps=1000, alpha=0.05):
    p_lower = regression_permutation_test(y, x, -equiv_bound, reps=reps, direction="greater")
    p_upper = regression_permutation_test(y, x, equiv_bound, reps=reps, direction="less")
    # Equivalence is accepted if both one-sided p-values are less than alpha
    equivalence = (p_lower < alpha) and (p_upper < alpha)
    return equivalence, p_lower, p_upper

# Set-up

variable_names = ['diff_vote_share_pis', 'diff_vote_share_left_oppo', 'diff_vote_share_right_oppo', 'diff_turnout' , 'dist_to_treated_boundary2023', 'Year', 'partial_treated2019', 'treated2019'] 

df = pd.DataFrame({var: Data.get(var=var, missingval=np.nan) for var in variable_names})
df2 = df[(df['Year'] == 2023) & (df['partial_treated2019'] == 0)]
rd_vars = ['diff_vote_share_pis', 'diff_vote_share_left_oppo', 'diff_vote_share_right_oppo', 'diff_turnout']
reps = int(Macro.getGlobal('reps'))
tv = 'treated2019'
windows = [[-5.50, 3.49], [-15, 15], [-20, 20], [-25, 25]]

ci_bounds = {
    'diff_vote_share_pis': 0.01,
    'diff_vote_share_left_oppo': 0.01,
    'diff_vote_share_right_oppo': 0.005,
    'diff_turnout': 0.01,
}

# Directory, file definitions

output_dir = "Tables"
output_file = "Table_B2.txt"
output_path = os.path.join(output_dir, output_file)
os.makedirs(output_dir, exist_ok=True)

# Perform randomization inference

with open(output_path, 'a') as f:
	for dv in rd_vars:

		ci_bound_current = ci_bounds[dv]

		for w0, w1 in windows:
			condition = ((df2['dist_to_treated_boundary2023'] > w0) & (df2['dist_to_treated_boundary2023'] < w1))

			equivalence, p_lower, p_upper = equivalence_test(df2.loc[condition, dv], df2.loc[condition, [tv]],                                                          equiv_bound=ci_bound_current, reps=reps, alpha=0.05)

			ci_equivalence = find_ci_equivalence(df2.loc[condition, dv], df2.loc[condition, [tv]], step=0.001, reps=reps)

			output_str = (f"DV: {dv}. Windows: [{w0}, {w1}]. "
                          f"Equivalence Range: {ci_bound_current}. "
                          f"P_lower: {p_lower}, p_upper: {p_upper}. "
                          f"Equivalence CI: [{ci_equivalence[0]:.3f}, {ci_equivalence[1]:.3f}]\n")
			
			print(output_str.strip())
			f.write(output_str)
		f.write("\n")
end

***********************************
***********************************
***********************************



***********************************
**# Table B.3: RDD: Balance on 2019 Pre-Treatment
***********************************

frame change data2019

local covs "parl_district6 parl_district7 parl_district18 parl_district24" // control for electoral districts within 30km
local if = "if partial_treated == 0"
local opts = "kernel(triangular) p(0)"

local i = 1
foreach bw in 15 20 25 {
	qui eststo rd2019_1_`i': rdrobust vote_share_pis dist_to_treated_boundary `if', c(0) `opts' covs(`covs') h(`bw' `bw')
	estadd scalar N_h = e(N_h_l) + e(N_h_r) 
	qui eststo rd2019_2_`i':rdrobust vote_share_left_oppo dist_to_treated_boundary `if', c(0) `opts' covs(`covs') h(`bw' `bw') 
	estadd scalar N_h = e(N_h_l) + e(N_h_r) 
	qui eststo rd2019_3_`i':rdrobust vote_share_right_oppo dist_to_treated_boundary `if', c(0) `opts' covs(`covs') h(`bw' `bw') 
	estadd scalar N_h = e(N_h_l) + e(N_h_r) 
	qui eststo rd2019_4_`i': rdrobust turnout dist_to_treated_boundary `if', c(0) `opts' covs(`covs') h(`bw' `bw')
	estadd scalar N_h = e(N_h_l) + e(N_h_r) 
	local i = `i' + 1
}

capture mkdir "Tables"

esttab rd2019_1_1 rd2019_2_1 rd2019_3_1 rd2019_4_1 using "Tables/Table_B3.tex", label collabels(none) cells(b(star fmt(3) vacant({--})) se(par(( )) fmt(3))) stats(N_h, fmt(0) labels(`"Observations"' )) varlabel(RD_Estimate "LATE")  mgroups("\shortstack{PiS\\Vote Share\\(2019)}" "\shortstack{Left Opposition\\Vote Share\\(2019)}" "\shortstack{Right Opposition\\Vote Share\\(2019)}" "\shortstack{Turnout\\(2019)}", pattern(1 1 1 1) span erepeat(\cmidrule(lr){@span}) prefix(\multicolumn{@span}{c}{) suffix(})) prehead(`"\begin{table}[htbp]\centering\small"' `"\setlength\tabcolsep{0pt}"' `"\caption{@title}"' `"\label{table:balance:2019}"' `"\begin{tabularx}{1.0\hsize}{l *{@E}{Y}}"' `"\toprule"') posthead("\\ \hline \\ \multicolumn{@span}{c}{\textbf{Panel A: 15-kilometer bandwidth}} \\\\[-1ex]") postfoot("")  title("Balance on Pre-treatment Characteristics") eqlabels(none) booktabs replace prefoot("\\") nonumbers nomtitles

esttab rd2019_1_2 rd2019_2_2 rd2019_3_2 rd2019_4_2 using "Tables/Table_B3.tex", f legend label collabels(none) cells(b(star fmt(3) vacant({--})) se(par(( )) fmt(3))) stats(N_h, fmt(0) labels(`"Observations"')) varlabel(RD_Estimate "LATE")   posthead("\\ \hline \\ \multicolumn{@span}{c}{\textbf{Panel B: 20-kilometer bandwidth}} \\\\[-1ex]") booktabs append nonumbers nomtitles prefoot("\\") eqlabels(, begin(" " "") nofirst)

esttab rd2019_1_3 rd2019_2_3 rd2019_3_3 rd2019_4_3 using "Tables/Table_B3.tex", f legend label collabels(none) cells(b(star fmt(3) vacant({--})) se(par(( )) fmt(3))) stats(N_h, fmt(0) labels(`"Observations"')) varlabel(RD_Estimate "LATE")  posthead("\\ \hline \\ \multicolumn{@span}{c}{\textbf{Panel C: 25-kilometer bandwidth}} \\\\[-1ex]") postfoot(`"\\ \bottomrule"' `"\multicolumn{@span}{p{\linewidth}}{\footnotesize \emph{Notes}: All models control for electoral district fixed effects. All estimators are constructed using a zero-order local polynomial and a triangular kernel. Standard errors are reported in parentheses. * p$<$0.05, ** p$<$0.01, *** p$<$0.001}\\"' `"\end{tabularx}"' `"\end{table}"') booktabs append nonumbers  nomtitles prefoot("\\") eqlabels(, begin(" " "") nofirst)

***********************************
***********************************
***********************************	



***********************************
**# Table B.4: Results Based on 2023 RDD
***********************************

frame change data2023

local covs "parl_district6 parl_district7 parl_district18 parl_district24" // control for electoral districts within 30km
local if = "if partial_treated == 0"
local opts = "kernel(triangular) p(0)"

local i = 1
foreach bw in 15 20 25 {
	qui eststo rd2023_1_`i': rdrobust vote_share_pis dist_to_treated_boundary `if', c(0) `opts' covs(`covs') h(`bw' `bw')
	estadd scalar N_h = e(N_h_l) + e(N_h_r) 
	qui eststo rd2023_2_`i':rdrobust vote_share_left_oppo dist_to_treated_boundary `if', c(0) `opts' covs(`covs') h(`bw' `bw') 
	estadd scalar N_h = e(N_h_l) + e(N_h_r) 
	qui eststo rd2023_3_`i':rdrobust vote_share_right_oppo dist_to_treated_boundary `if', c(0) `opts' covs(`covs') h(`bw' `bw') 
	estadd scalar N_h = e(N_h_l) + e(N_h_r) 
	qui eststo rd2023_4_`i': rdrobust turnout dist_to_treated_boundary `if', c(0) `opts' covs(`covs') h(`bw' `bw')
	estadd scalar N_h = e(N_h_l) + e(N_h_r) 
	local i = `i' + 1
}

capture mkdir "Tables"

esttab rd2023_1_1 rd2023_2_1 rd2023_3_1 rd2023_4_1 using "Tables/Table_B4.tex", label collabels(none) cells(b(star fmt(3) vacant({--})) se(par(( )) fmt(3))) stats(N_h, fmt(0) labels(`"Observations"' )) varlabel(RD_Estimate "LATE")  mgroups("\shortstack{PiS\\Vote Share\\(2023)}" "\shortstack{Left Opposition\\Vote Share\\(2023)}" "\shortstack{Right Opposition\\Vote Share\\(2023)}" "\shortstack{Turnout\\(2023)}", pattern(1 1 1 1) span erepeat(\cmidrule(lr){@span}) prefix(\multicolumn{@span}{c}{) suffix(})) prehead(`"\begin{table}[htbp]\centering\small"' `"\setlength\tabcolsep{0pt}"' `"\caption{@title}"' `"\label{table:results:rdd:2023}"' `"\begin{tabularx}{1.0\hsize}{l *{@E}{Y}}"' `"\toprule"') posthead("\\ \hline \\ \multicolumn{@span}{c}{\textbf{Panel A: 15-kilometer bandwidth}} \\\\[-1ex]") postfoot("")  title("Results Based on Regression Discontinuity Design") eqlabels(none) booktabs replace prefoot("\\") nonumbers nomtitles

esttab rd2023_1_2 rd2023_2_2 rd2023_3_2 rd2023_4_2 using "Tables/Table_B4.tex", f legend label collabels(none) cells(b(star fmt(3) vacant({--})) se(par(( )) fmt(3))) stats(N_h, fmt(0) labels(`"Observations"')) varlabel(RD_Estimate "LATE")   posthead("\\ \hline \\ \multicolumn{@span}{c}{\textbf{Panel B: 20-kilometer bandwidth}} \\\\[-1ex]") booktabs append nonumbers nomtitles prefoot("\\") eqlabels(, begin(" " "") nofirst)

esttab rd2023_1_3 rd2023_2_3 rd2023_3_3 rd2023_4_3 using "Tables/Table_B4.tex", f legend label collabels(none) cells(b(star fmt(3) vacant({--})) se(par(( )) fmt(3))) stats(N_h, fmt(0) labels(`"Observations"')) varlabel(RD_Estimate "LATE")  posthead("\\ \hline \\ \multicolumn{@span}{c}{\textbf{Panel C: 25-kilometer bandwidth}} \\\\[-1ex]") postfoot(`"\\ \bottomrule"' `"\multicolumn{@span}{p{\linewidth}}{\footnotesize \emph{Notes}: All models control for electoral district fixed effects. All estimators are constructed using a zero-order local polynomial and a triangular kernel. Standard errors are reported in parentheses. * p$<$0.05, ** p$<$0.01, *** p$<$0.001}\\"' `"\end{tabularx}"' `"\end{table}"') booktabs append nonumbers  nomtitles prefoot("\\") eqlabels(, begin(" " "") nofirst)

***********************************
***********************************
***********************************	



***********************************
**# Appendix B.3.3: COMPARE DIFF-IN-DISC WITH RDD
***********************************

* NOTE: MUST RUN MAIN RESULTS AND RDD FIRST FOR THE CODE TO WORK PROPERLY. DO NOT RUN PRE-TREATMENT BALANCE CODE IMMIEDIATELY BEFORE RUNNING THIS CODE, AS THIS WILL RESULT IN AN INCORRECT COMPARISON.

** Define local macros
local varlist "diff_vote_share_pis diff_vote_share_left_oppo diff_vote_share_right_oppo diff_turnout"
local labels `""Pis Vote Share""Left Opposition Vote Share""Right Opposition Vote Share""Voter Turnout""'
local indices 1 2 3 4
local bandwidths 1 2 3
local km_labels "15 20 25"

** Create folder and open file
capture mkdir "Supplementary Analyses"
file open comparison using "Supplementary Analyses/Section_B3_3.txt", write replace

** Loop over each DV, bandwidth
foreach i of local indices {
    local var : word `i' of `varlist'
    local label : word `i' of `labels'

    foreach j of local bandwidths {
		local band_label : word `j' of `km_labels'
        
        *** Retrieve Diff-in-disc
        local diff_b = ${l`j'_`var'}
		local diff_z = invnormal(1 - ${p`j'_`var'} / 2)
        local diff_se = abs(`diff_b' / `diff_z')
        
        *** Retrieve RDD
		est restore rd2023_`i'_`j'
		local rd_b = e(tau_cl)
		local rd_se = e(se_tau_cl)
		
        *** Z-statistic and p-value
        local z_statistic = (`diff_b' - `rd_b') / sqrt(`diff_se'^2 + `rd_se'^2)
        local p_value = 2 * (1 - normal(abs(`z_statistic')))
        
        *** Report results
        di "`label' - `band_label'km. Z-statistic: " %5.2f `z_statistic' ". P-value: " %4.2f `p_value'
		file write comparison %9s ("`label' - `band_label'km. Z-statistic: ") %5.2f (`z_statistic') %9s (". P-value: ") %4.2f (`p_value') _n
    }
}

** Close file
file close comparison

***********************************
***********************************
***********************************	
	


***********************************
**# Table B.5: Pre-Treatment Balance on the Ukraine Placebo Border
***********************************

frame change data2015_2019

* Balance within the Ukraine placebo: balancing control and treated: create weights

preserve

keep if Year == 2019 & treated2019 == 0 & ukraine_placebo_partial2019 == 0
keep if abs(dist_to_ukr_placebo_boundary) <= 30

ebalance ukraine_placebo2019 diff_vote_share_pis diff_turnout diff_vote_share_left_oppo diff_vote_share_right_oppo voters population constituency_urban if abs(dist_to_ukr_placebo_boundary) <= 15, generate(eweight15)
ebalance ukraine_placebo2019 diff_vote_share_pis diff_turnout diff_vote_share_left_oppo diff_vote_share_right_oppo voters population constituency_urban if abs(dist_to_ukr_placebo_boundary) <= 20, generate(eweight20)
ebalance ukraine_placebo2019 diff_vote_share_pis diff_turnout diff_vote_share_left_oppo diff_vote_share_right_oppo voters population constituency_urban if abs(dist_to_ukr_placebo_boundary) <= 25, generate(eweight25)

keep polling_station_id2019 eweight15 eweight20 eweight25

tempfile weights
save `weights', replace

restore

merge m:1 polling_station_id2019 using `weights', nogen

** Randomization inference in Python
python:
from sfi import Data
from sfi import Macro
import pandas as pd
import numpy as np
import statsmodels.api as sm

# Define functions

def model_coef(y, x, weights=None):
    if weights is None:
        model = sm.OLS(y, sm.add_constant(x)).fit(cov_type='HC2')
    else:
        model = sm.WLS(y, sm.add_constant(x), weights=weights).fit(cov_type='HC2')
    model_coef = model.params.iloc[1]
    return model_coef


def get_pvalue(y, x, coef, reps=1000, weights=None, seed=666):
    permuted_coefs = []
    np.random.seed(seed)
    for _ in range(reps):
        x_permuted = np.random.permutation(x)
        if weights is None:
            permuted_model = sm.OLS(y, sm.add_constant(x_permuted)).fit(cov_type='HC2')
        else:
            permuted_model = sm.WLS(y, sm.add_constant(x_permuted), weights=weights).fit(cov_type='HC2')
        permuted_coef = permuted_model.params.iloc[1]
        permuted_coefs.append(permuted_coef)
    # Calculate the p-value as the proportion of permuted coefficients more extreme than the hypothesized value
    p_value = (np.abs(permuted_coefs) >= np.abs(coef)).mean()
    return p_value


def regression_permutation_test(y, x, treatment_effect, reps=1000, seed=666, weights=None):
    np.random.seed(seed) 
    X = sm.add_constant(x) 
    y_adjusted = y - X.iloc[:, 1] * treatment_effect  # Adjust outcomes based on the hypothesized treatment effect
    # Fit the model with adjusted outcomes
    if weights is not None:
        original_model = sm.WLS(y_adjusted, X, weights=weights).fit()
    else:
        original_model = sm.OLS(y_adjusted, X).fit()
    T_obs = original_model.params.iloc[1]
    permuted_T = []
    for _ in range(reps):
        # Permute the treatment assignment
        x_permuted = X.copy()
        x_permuted.iloc[:, 1] = np.random.permutation(x_permuted.iloc[:, 1])
        if weights is not None:
            permuted_model = sm.WLS(y_adjusted, x_permuted, weights=weights).fit()
        else:
            permuted_model = sm.OLS(y_adjusted, x_permuted).fit()
        T_perm = permuted_model.params.iloc[1]
        permuted_T.append(T_perm)
    # Two-sided p-value: Proportion of permuted statistics as extreme as the observed statistic
    p_value = np.mean([abs(T) >= abs(T_obs) for T in permuted_T])
    return p_value


def find_ci(y, x, effect_range, alpha=0.05, reps=1000, weights=None):
    ci_bounds = []
    for effect in effect_range:
        p_value = regression_permutation_test(y, x, effect, reps=reps, weights=weights)
        if p_value > alpha:
            ci_bounds.append(effect)
    return min(ci_bounds), max(ci_bounds)


variable_names = ['diff_vote_share_pis', 'diff_turnout', 'diff_vote_share_left_oppo', 'diff_vote_share_right_oppo' , 'population', 'voters', 'constituency_urban', 'Year', 'partial_treated2019', 'treated2019', 'ukraine_placebo_partial2019', 'dist_to_treated_boundary2019', 'dist_to_ukr_placebo_boundary2019', 'ukraine_placebo2019', 'eweight15', 'eweight20', 'eweight25']

# Set-up
df = pd.DataFrame({var: Data.get(var) for var in variable_names})
df2 = df[(df['Year'] == 2019) & (df['treated2019'] == 0) & (df['ukraine_placebo_partial2019'] == 0)]
rd_vars = ['diff_vote_share_pis', 'diff_turnout', 'diff_vote_share_left_oppo', 'diff_vote_share_right_oppo' , 'population', 'voters', 'constituency_urban']
reps = int(Macro.getGlobal('reps'))
tv = 'ukraine_placebo2019'
weight_name = 'eweight'
windows = [15, 20, 25]

ci_vecs = {
    'diff_vote_share_pis': np.arange(-0.07, 0.07, 0.001),
    'diff_vote_share_left_oppo': np.arange(-0.06, 0.06, 0.001),
    'diff_vote_share_right_oppo': np.arange(-0.045, 0.045, 0.001),
    'diff_turnout': np.arange(-0.045, 0.045, 0.001),
    'population': np.arange(-300, 260, 10),
    'voters': np.arange(-250, 250, 10),
    'constituency_urban': np.arange(-0.17, 0.15, 0.001)
}

# Perform randomization inference

for dv in rd_vars:
	
	ci_vec_current = ci_vecs[dv]
	
	for w in windows:
	
		weight_column = f'{weight_name}{w}'
		condition = (abs(df2['dist_to_ukr_placebo_boundary2019']) < w)
		combined_condition = condition & (df2[weight_column] != 0)

		coef = model_coef(df2.loc[condition, dv], df2.loc[condition, [tv]], weights=df2.loc[condition, weight_column])
		pvalue = get_pvalue(df2.loc[condition, dv], df2.loc[condition, [tv]], coef, reps=reps, weights=df2.loc[condition, weight_column])
		n_treated = df2[combined_condition][tv].value_counts().get(1, 0)
		n_control = df2[combined_condition][tv].value_counts().get(0, 0)
		ci = find_ci(df2.loc[condition, dv], df2.loc[condition, [tv]], effect_range=ci_vec_current, reps=reps, weights=df2.loc[condition, weight_column])
	
		Macro.setGlobal(f'l{w}_{dv}', str(coef))
		Macro.setGlobal(f'p{w}_{dv}', str(pvalue))
		Macro.setGlobal(f'cl{w}_{dv}', str(ci[0]))
		Macro.setGlobal(f'cr{w}_{dv}', str(ci[1]))
		Macro.setGlobal(f'nl{w}_{dv}', str(n_control))
		Macro.setGlobal(f'nr{w}_{dv}', str(n_treated))
	
end


* Re-Define labels
label var diff_vote_share_pis "$\Delta$ PiS Vote Share (2015-2019)"
label var diff_vote_share_left_oppo "$\Delta$ Left Opposition Vote Share (2015-2019)"
label var diff_vote_share_right_oppo "$\Delta$ Right Opposition Vote Share (2015-2019)"
label var diff_turnout "$\Delta$ Turnout (2015-2019)"
label var population "Population (2019)"
label var voters "Registered Voters (2019)"
label var constituency_urban "Urban Constituency (Yes=1) (2019)"

** Generating table
capture mkdir "Tables"
local vars diff_vote_share_pis diff_vote_share_left_oppo diff_vote_share_right_oppo diff_turnout population voters constituency_urban
local ascii_code 65
texdoc init "Tables/Table_B5.tex", replace force
tex \begin{table}[htbp]
tex \small
tex \caption{Pre-treatment Balance Test --- Ukraine Placebo}
tex \vspace{-15pt}
tex \label{table:pretreatment:balance:test:ukraine}
tex \begin{tabularx}{\textwidth}{l *{3}{Y}}
tex \toprule
tex & \multicolumn{3}{c}{Manual Windows}\\
tex \cmidrule(lr){2-4}
tex & \([-15, 15]\) & \([-20, 20]\) & \([-25, 25]\) \\
tex \midrule
foreach var of varlist `vars' {
	local panel_letter = char(`ascii_code')
	global lbe_`var' : var label `var'
	foreach v in l15 l20 l25 cl15 cl20 cl25 cr15 cr20 cr25 {
        local `v'_`var': di %9.3f ${`v'_`var'}
    }
    foreach v in p15 p20 p25 {
		local `v'_`var': di %9.2f ${`v'_`var'}
    }
	foreach v in nl15 nr15 nl20 nr20 nl25 nr25 {
		local `v'_`var': di %9.0f ${`v'_`var'}
    }
	tex \multicolumn{4}{l}{\textbf{Panel `panel_letter'. ${lbe_`var'}}} \\
	tex \midrule
    tex LATE & `l15_`var'' & `l20_`var'' & `l25_`var'' \\
    tex P-value & `p15_`var'' & `p20_`var'' & `p25_`var'' \\
    tex 95\% CI & [`cl15_`var'', `cr15_`var''] & [`cl20_`var'', `cr20_`var''] & [`cl25_`var'', `cr25_`var''] \\
	tex \midrule
	local ++ascii_code
}
tex N treated &`nr15_diff_vote_share_pis' & `nr20_diff_vote_share_pis' & `nr25_diff_vote_share_pis' \\
tex N control & `nl15_diff_vote_share_pis' & `nl20_diff_vote_share_pis' & `nl25_diff_vote_share_pis'\\
tex \bottomrule
tex \multicolumn{4}{p{\linewidth}}{\footnotesize \emph{Notes}: Table presents results of a pre-treatment balance test on the Ukraine placebo. Randomization-based inference results are obtained using a procedure developed by the authors that mimics \emph{rdrandinf} by \citet{cattaneo_titiunik_vazquez_bare2016} but allows for the use of weights. Control observations are reweighted using weights obtained from \citet{hainmueller2012} entropy balancing. LATE point estimates reflect the unadjusted difference in means between treatment and control groups using a uniform kernel. P-values and 95\% confidence (estimated by inversion) are obtained through a Fisherian finite-sample exact randomization test of a sharp null hypothesis of no treatment effects based on 10,000 replications.}\\
tex \end{tabularx}
tex \end{table}
texdoc close

***********************************
***********************************
***********************************
	
	

***********************************
**# Table B.6: Ukraine Placebo Results
***********************************

frame change data2015_2019

* Balance within the Ukraine placebo: balancing control and treated: create weights based on pre-treatment variables

preserve
keep if Year == 2019 & treated2019 == 0 & ukraine_placebo_partial2019 == 0
keep if abs(dist_to_ukr_placebo_boundary) <= 30
ebalance ukraine_placebo2019 diff_vote_share_pis diff_turnout diff_vote_share_left_oppo diff_vote_share_right_oppo voters population constituency_urban if abs(dist_to_ukr_placebo_boundary) <= 15, generate(eweight15)
ebalance ukraine_placebo2019 diff_vote_share_pis diff_turnout diff_vote_share_left_oppo diff_vote_share_right_oppo voters population constituency_urban if abs(dist_to_ukr_placebo_boundary) <= 20, generate(eweight20)
ebalance ukraine_placebo2019 diff_vote_share_pis diff_turnout diff_vote_share_left_oppo diff_vote_share_right_oppo voters population constituency_urban if abs(dist_to_ukr_placebo_boundary) <= 25, generate(eweight25)
ebalance ukraine_placebo2019 diff_vote_share_pis diff_turnout diff_vote_share_left_oppo diff_vote_share_right_oppo voters population constituency_urban if dist_to_ukr_placebo_boundary >= -5.50 & dist_to_ukr_placebo_boundary <= 3.49, generate(eweightdd)
keep polling_station_id2019 eweight15 eweight20 eweight25 eweightdd
tempfile weights
save `weights', replace
restore

frame change data2019_2023

merge m:1 polling_station_id2019 using `weights'
drop if _merge == 2
drop _merge

** Randomization inference in Python
python:
from sfi import Data
from sfi import Macro
import pandas as pd
import numpy as np
import statsmodels.api as sm

# Define functions

def model_coef(y, x, weights=None):
    if weights is None:
        model = sm.OLS(y, sm.add_constant(x)).fit(cov_type='HC2')
    else:
        model = sm.WLS(y, sm.add_constant(x), weights=weights).fit(cov_type='HC2')
    model_coef = model.params.iloc[1]
    return model_coef


def get_pvalue(y, x, coef, reps=1000, weights=None, seed=666):
    permuted_coefs = []
    np.random.seed(seed)
    for _ in range(reps):
        x_permuted = np.random.permutation(x)
        if weights is None:
            permuted_model = sm.OLS(y, sm.add_constant(x_permuted)).fit(cov_type='HC2')
        else:
            permuted_model = sm.WLS(y, sm.add_constant(x_permuted), weights=weights).fit(cov_type='HC2')
        permuted_coef = permuted_model.params.iloc[1]
        permuted_coefs.append(permuted_coef)
    # Calculate the p-value as the proportion of permuted coefficients more extreme than the hypothesized value
    p_value = (np.abs(permuted_coefs) >= np.abs(coef)).mean()
    return p_value


def regression_permutation_test(y, x, treatment_effect, reps=1000, seed=666, weights=None):
    np.random.seed(seed) 
    X = sm.add_constant(x)
    y_adjusted = y - X.iloc[:, 1] * treatment_effect  # Adjust outcomes based on the hypothesized treatment effect
    # Fit the model with adjusted outcomes
    if weights is not None:
        original_model = sm.WLS(y_adjusted, X, weights=weights).fit()
    else:
        original_model = sm.OLS(y_adjusted, X).fit()
    T_obs = original_model.params.iloc[1]
    permuted_T = []
    for _ in range(reps):
        # Permute the treatment assignment
        x_permuted = X.copy()
        x_permuted.iloc[:, 1] = np.random.permutation(x_permuted.iloc[:, 1])
        if weights is not None:
            permuted_model = sm.WLS(y_adjusted, x_permuted, weights=weights).fit()
        else:
            permuted_model = sm.OLS(y_adjusted, x_permuted).fit()
        T_perm = permuted_model.params.iloc[1]
        permuted_T.append(T_perm)
    # Two-sided p-value: Proportion of permuted statistics as extreme as the observed statistic
    p_value = np.mean([abs(T) >= abs(T_obs) for T in permuted_T])
    return p_value


def find_ci(y, x, effect_range, alpha=0.05, reps=1000, weights=None):
    ci_bounds = []
    for effect in effect_range:
        p_value = regression_permutation_test(y, x, effect, reps=reps, weights=weights)
        if p_value > alpha:
            ci_bounds.append(effect)
    return min(ci_bounds), max(ci_bounds)


variable_names = ['diff_vote_share_pis', 'diff_turnout', 'diff_vote_share_left_oppo', 'diff_vote_share_right_oppo', 'Year', 'partial_treated2019', 'treated2019', 'ukraine_placebo_partial2019', 'dist_to_treated_boundary2023', 'dist_to_ukr_placebo_boundary2023', 'ukraine_placebo2019', 'eweight15', 'eweight20', 'eweight25', 'eweightdd']

# Set-up
df = pd.DataFrame({var: Data.get(var=var, missingval=np.nan) for var in variable_names})
df2 = df[(df['Year'] == 2023) & (df['treated2019'] == 0) & (df['ukraine_placebo_partial2019'] == 0)]
rd_vars = ['diff_vote_share_pis', 'diff_turnout', 'diff_vote_share_left_oppo', 'diff_vote_share_right_oppo']
reps = int(Macro.getGlobal('reps'))
tv = 'ukraine_placebo2019'
weight_name = 'eweight'
windows = [15, 20, 25, 'dd']


ci_vecs = {
    'diff_vote_share_pis': np.arange(-0.03, 0.055, 0.001),
    'diff_vote_share_left_oppo': np.arange(-0.04, 0.04, 0.001),
    'diff_vote_share_right_oppo': np.arange(-0.03, 0.02, 0.001),
    'diff_turnout': np.arange(-0.015, 0.045, 0.001),
}

# Perform randomization inference

for dv in rd_vars:
	ci_vec_current = ci_vecs[dv]
	
	for w in windows:
		weight_column = f'{weight_name}{w}'
		condition = (df2[weight_column] != 0)  & (df2[weight_column].isna() == False)
		weight = df2.loc[condition, [weight_column]]

		coef = model_coef(df2.loc[condition, dv], df2.loc[condition, [tv]], weights=weight)
		pvalue = get_pvalue(df2.loc[condition, dv], df2.loc[condition, [tv]], coef, reps=reps, weights=weight)
		n_treated = df2[condition][tv].value_counts().get(1, 0)
		n_control = df2[condition][tv].value_counts().get(0, 0)
		ci = find_ci(df2.loc[condition, dv], df2.loc[condition, [tv]], effect_range=ci_vec_current, reps=reps, weights=weight)

		Macro.setGlobal(f'l{w}_{dv}', str(coef))
		Macro.setGlobal(f'p{w}_{dv}', str(pvalue))
		Macro.setGlobal(f'cl{w}_{dv}', str(ci[0]))
		Macro.setGlobal(f'cr{w}_{dv}', str(ci[1]))
		Macro.setGlobal(f'nl{w}_{dv}', str(n_control))
		Macro.setGlobal(f'nr{w}_{dv}', str(n_treated))
end

* Re-Define labels
label var diff_vote_share_pis "$\Delta$ PiS Vote Share (2019-2023)"
label var diff_vote_share_left_oppo "$\Delta$ Left Opposition Vote Share (2019-2023)"
label var diff_vote_share_right_oppo "$\Delta$ Right Opposition Vote Share (2019-2023)"
label var diff_turnout "$\Delta$ Turnout (2019-2023)"

** Generating table
capture mkdir "Tables"
local vars diff_vote_share_pis diff_vote_share_left_oppo diff_vote_share_right_oppo diff_turnout 
local ascii_code 65
texdoc init "Tables/Table_B6.tex", replace force
tex \begin{table}[htbp]
tex \small
tex \caption{Results --- Ukraine Placebo}
tex \vspace{-15pt}
tex \label{table:results:ukraine}
tex \begin{tabularx}{\textwidth}{l *{4}{Y}}
tex \toprule
tex & \multicolumn{3}{c}{Manual Windows} & \multicolumn{1}{c}{Data-driven}\\
tex \cmidrule(lr){2-4} \cmidrule(lr){5-5}
tex & \([-15, 15]\) & \([-20, 20]\) & \([-25, 25]\)  & \([-5.50, 3.49]\) \\
tex \midrule
foreach var of varlist `vars' {
	local panel_letter = char(`ascii_code')
	global lbe_`var' : var label `var'
	foreach v in l15 l20 l25 ldd cl15 cl20 cl25 cldd cr15 cr20 cr25 crdd {
        local `v'_`var': di %9.3f ${`v'_`var'}
    }
    foreach v in p15 p20 p25 pdd {
		local `v'_`var': di %9.2f ${`v'_`var'}
    }
	foreach v in nl15 nr15 nl20 nr20 nl25 nr25 nldd nrdd {
		local `v'_`var': di %9.0f ${`v'_`var'}
    }
	tex \multicolumn{5}{l}{\textbf{Panel `panel_letter'. ${lbe_`var'}}} \\
	tex \midrule
    tex LATE & `l15_`var'' & `l20_`var'' & `l25_`var'' & `ldd_`var'' \\
    tex P-value & `p15_`var'' & `p20_`var'' & `p25_`var'' & `pdd_`var'' \\
    tex 95\% CI & [`cl15_`var'', `cr15_`var''] & [`cl20_`var'', `cr20_`var''] & [`cl25_`var'', `cr25_`var''] & [`cldd_`var'', `crdd_`var''] \\
	tex \midrule
	local ++ascii_code
}
tex N treated & `nr15_diff_vote_share_pis' & `nr20_diff_vote_share_pis' & `nr25_diff_vote_share_pis' & `nrdd_diff_vote_share_pis' \\
tex N control & `nl15_diff_vote_share_pis' & `nl20_diff_vote_share_pis' & `nl25_diff_vote_share_pis' & `nr25_diff_vote_share_pis' \\
tex \bottomrule
tex \multicolumn{5}{p{\linewidth}}{\footnotesize \emph{Notes}: Table presents results for the Ukraine placebo test. Randomization-based inference results are obtained using a procedure developed by the authors that mimics \emph{rdrandinf} by \citet{cattaneo_titiunik_vazquez_bare2016} but allows for the use of weights. Control observations are reweighted using weights obtained from \citet{hainmueller2012} entropy balancing. LATE point estimates reflect the unadjusted difference in means between treatment and control groups using a uniform kernel. P-values and 95\% confidence (estimated by inversion) are obtained through a Fisherian finite-sample exact randomization test of a sharp null hypothesis of no treatment effects based on 10,000 replications.}\\
tex \end{tabularx}
tex \end{table}
texdoc close

***********************************
***********************************
***********************************
	
	

***********************************
**# Table B.7: Robustness: Non-registered Voters Share
***********************************

frame change data2019_2023

* Conduct randomization inference and generate confidence intervals

** Note: we utilize the Python implementation of rdrandinf because of the computationally-intensive nature of the task

python:
from sfi import Data
from sfi import Macro
from rdlocrand import rdrandinf, rdwinselect
import pandas as pd
import numpy as np

variable_names = ['diff_nonreg_share', 'diff_vote_share_pis', 'diff_vote_share_left_oppo', 'diff_vote_share_right_oppo', 'diff_turnout', 'dist_to_treated_boundary2023', 'Year', 'partial_treated2019'] 

df = pd.DataFrame({var: Data.get(var) for var in variable_names})
df2 = df[(df['Year'] == 2023) & (df['partial_treated2019'] == 0)]

rd_vars = ['diff_nonreg_share']
balance_covs = df2[['diff_vote_share_pis', 'diff_vote_share_left_oppo', 'diff_vote_share_right_oppo', 'diff_turnout']].to_numpy()
reps = int(Macro.getGlobal('reps'))

ci_vecs = {
	'diff_nonreg_share': np.concatenate(([0.05], np.arange(-0.5, 0.05, 0.001))),
}

for rd_var in rd_vars:
    ci_vec_current = ci_vecs[rd_var]

    out = rdrandinf(df2[rd_var], df2['dist_to_treated_boundary2023'], wl=-15, wr=15, reps=reps, ci=ci_vec_current)
	
    Macro.setGlobal(f'l1_{rd_var}', str(out['obs.stat'][0]))
    Macro.setGlobal(f'p1_{rd_var}', str(out['p.value']))
    Macro.setGlobal(f'wl1_{rd_var}', str(out['window'][0]))
    Macro.setGlobal(f'wr1_{rd_var}', str(out['window'][1]))
    Macro.setGlobal(f'cil1_{rd_var}', str(out['ci'][0][0]))
    Macro.setGlobal(f'cir1_{rd_var}', str(out['ci'][0][1]))
    Macro.setGlobal(f'nl1_{rd_var}', str(out['sumstats'][1][0]))
    Macro.setGlobal(f'nr1_{rd_var}', str(out['sumstats'][1][1]))

    out = rdrandinf(df2[rd_var], df2['dist_to_treated_boundary2023'], wl=-20, wr=20, reps=reps, ci=ci_vec_current)

    Macro.setGlobal(f'l2_{rd_var}', str(out['obs.stat'][0]))
    Macro.setGlobal(f'p2_{rd_var}', str(out['p.value']))
    Macro.setGlobal(f'wl2_{rd_var}', str(out['window'][0]))
    Macro.setGlobal(f'wr2_{rd_var}', str(out['window'][1]))
    Macro.setGlobal(f'cil2_{rd_var}', str(out['ci'][0][0]))
    Macro.setGlobal(f'cir2_{rd_var}', str(out['ci'][0][1]))
    Macro.setGlobal(f'nl2_{rd_var}', str(out['sumstats'][1][0]))
    Macro.setGlobal(f'nr2_{rd_var}', str(out['sumstats'][1][1]))

    out = rdrandinf(df2[rd_var], df2['dist_to_treated_boundary2023'], wl=-25, wr=25, reps=reps, ci=ci_vec_current)

    Macro.setGlobal(f'l3_{rd_var}', str(out['obs.stat'][0]))
    Macro.setGlobal(f'p3_{rd_var}', str(out['p.value']))
    Macro.setGlobal(f'wl3_{rd_var}', str(out['window'][0]))
    Macro.setGlobal(f'wr3_{rd_var}', str(out['window'][1]))
    Macro.setGlobal(f'cil3_{rd_var}', str(out['ci'][0][0]))
    Macro.setGlobal(f'cir3_{rd_var}', str(out['ci'][0][1]))
    Macro.setGlobal(f'nl3_{rd_var}', str(out['sumstats'][1][0]))
    Macro.setGlobal(f'nr3_{rd_var}', str(out['sumstats'][1][1]))

    out = rdrandinf(df2[rd_var], df2['dist_to_treated_boundary2023'], reps=reps, ci=ci_vec_current, level=0.15,
                    nwindows=20, wobs=5, obsmin=7, wasymmetric=True, covariates=balance_covs)

    Macro.setGlobal(f'l4_{rd_var}', str(out['obs.stat'][0]))
    Macro.setGlobal(f'p4_{rd_var}', str(out['p.value']))
    Macro.setGlobal(f'wl4_{rd_var}', str(out['window'][0]))
    Macro.setGlobal(f'wr4_{rd_var}', str(out['window'][1]))
    Macro.setGlobal(f'cil4_{rd_var}', str(out['ci'][0][0]))
    Macro.setGlobal(f'cir4_{rd_var}', str(out['ci'][0][1]))
    Macro.setGlobal(f'nl4_{rd_var}', str(out['sumstats'][1][0]))
    Macro.setGlobal(f'nr4_{rd_var}', str(out['sumstats'][1][1]))
end

* Re-Define labels
label var diff_nonreg_share "$\Delta$ Non-resident Voter Share (2019-2023)"

* Generating table
capture mkdir "Tables"
local vars diff_nonreg_share
local ascii_code 65
local wl4_diff_nonreg_share: di %9.2f $wl4_diff_nonreg_share
local wr4_diff_nonreg_share: di %9.2f $wr4_diff_nonreg_share
texdoc init "Tables/Table_B7.tex", replace force
tex \begin{table}[htbp]
tex \small
tex \caption{Robustness: Non-resident Voters}
tex \vspace{-15pt}
tex \label{table:nonreg:voters:share}
tex \begin{tabularx}{\textwidth}{l *{4}{Y}}
tex \toprule
tex & \multicolumn{3}{c}{Manual Windows} & \multicolumn{1}{c}{Data-driven} \\
tex \cmidrule(lr){2-4} \cmidrule(lr){5-5}
tex & \([$wl1_diff_nonreg_share, $wr1_diff_nonreg_share]\) & \([$wl2_diff_nonreg_share, $wr2_diff_nonreg_share]\) & \([$wl3_diff_nonreg_share, $wr3_diff_nonreg_share]\) & \([`wl4_diff_nonreg_share',`wr4_diff_nonreg_share']\) \\
tex \midrule
foreach var of varlist `vars' {
	local panel_letter = char(`ascii_code')
	global lbe_`var' : var label `var'
	foreach v in l1 l2 l3 l4 cil1 cil2 cil3 cil4 cir1 cir2 cir3 cir4 {
        local `v'_`var': di %9.3f ${`v'_`var'}
    }
    foreach v in p1 p2 p3 p4 {
		local `v'_`var': di %9.3f ${`v'_`var'}
    }
	foreach v in nl1 nr1 nl2 nr2 nl3 nr3 nl4 nr4 {
		local `v'_`var': di %9.0f ${`v'_`var'}
    }
	tex \multicolumn{5}{l}{\textbf{Panel `panel_letter'. ${lbe_`var'}}} \\
	tex \midrule
    tex LATE & `l1_`var'' & `l2_`var'' & `l3_`var'' & `l4_`var'' \\
    tex P-value & `p1_`var'' & `p2_`var'' & `p3_`var'' & `p4_`var'' \\
    tex 95\% CI & [`cil1_`var'', `cir1_`var''] & [`cil2_`var'', `cir2_`var''] & [`cil3_`var'', `cir3_`var''] & [`cil4_`var'', `cir4_`var''] \\
	tex \midrule
	local ++ascii_code
}
tex N treated &`nr1_diff_nonreg_share' & `nr2_diff_nonreg_share' & `nr3_diff_nonreg_share' & `nr4_diff_nonreg_share' \\
tex N control & `nl1_diff_nonreg_share' & `nl2_diff_nonreg_share' & `nl3_diff_nonreg_share' & `nl4_diff_nonreg_share' \\
tex \bottomrule
tex \multicolumn{5}{p{\linewidth}}{\footnotesize \emph{Notes}: Table presents results on the relationship between treatment and non-resident voters share. Randomization-based inference results are obtained using the Python implementation of \emph{rdrandinf} by \citet{cattaneo_titiunik_vazquez_bare2016}. LATE point estimates reflect the unadjusted difference in means between treated and control observations using a uniform kernel. P-values and 95\% confidence intervals (estimated by inversion) are obtained through a Fisherian finite-sample exact randomization test of a sharp null hypothesis of no treatment effects based on 10,000 replications. Data-driven window is selected using the \emph{rdwinselect} command by \citet{cattaneo_titiunik_vazquez_bare2016} and reflects the largest window around the cutoff such that the minimum p-value on the balance test across the four primary first-differenced outcome variables is larger than 0.15.}\\
tex \end{tabularx}
tex \end{table}
texdoc close

***********************************
***********************************
***********************************



***********************************
**# Figure B1: Sensitivity Analysis
***********************************

frame change data2019_2023

* Conduct randomization inference and generate confidence intervals

** Note: we utilize the Python implementation of rdrandinf because of the computationally-intensive nature of the task

python:
from sfi import Data, Macro, Frame, SFIToolkit
from rdlocrand import rdrandinf, rdwinselect
import pandas as pd
import numpy as np

variable_names = ['diff_vote_share_pis', 'diff_vote_share_left_oppo', 'diff_vote_share_right_oppo', 'diff_turnout', 'votes_pis2019', 'votes_pis2023', 'votes_valid2019', 'votes_valid2023', 'nonregistered_voters2019', 'nonregistered_voters2023', 'dist_to_treated_boundary2023', 'Year', 'partial_treated2019'] 

df = pd.DataFrame({var: Data.get(var) for var in variable_names})
df2 = df[(df['Year'] == 2023) & (df['partial_treated2019'] == 0)]


balance_covs = df2[['diff_vote_share_pis', 'diff_vote_share_left_oppo', 'diff_vote_share_right_oppo', 'diff_turnout']].to_numpy()
reps = int(Macro.getGlobal('reps'))

shares = np.arange(0, 1.01, 0.01)
ci_vec = np.concatenate(([0.05], np.arange(-0.055, 0.03, 0.001)))

share_nonres_pis = []
adj_ate15 = []
adj_ci_low15 = []
adj_ci_high15 = []
adj_ate20 = []
adj_ci_low20 = []
adj_ci_high20 = []
adj_ate25 = []
adj_ci_low25 = []
adj_ci_high25 = []
adj_ate_data = []
adj_ci_low_data = []
adj_ci_high_data = []

rd_var = 'diff_vote_share_pis'

out = rdrandinf(df2[rd_var], df2['dist_to_treated_boundary2023'], wl=-15, wr=15, reps=reps, ci=ci_vec)
t_ate15 = float(out['obs.stat'][0])
t_ci_low15 = float(out['ci'][0][0])
t_ci_high15 = float(out['ci'][0][1])
out = rdrandinf(df2[rd_var], df2['dist_to_treated_boundary2023'], wl=-20, wr=20, reps=reps, ci=ci_vec)
t_ate20 = float(out['obs.stat'][0])
t_ci_low20 = float(out['ci'][0][0])
t_ci_high20 = float(out['ci'][0][1])
out = rdrandinf(df2[rd_var], df2['dist_to_treated_boundary2023'], wl=-25, wr=25, reps=reps, ci=ci_vec)
t_ate25 = float(out['obs.stat'][0])
t_ci_low25 = float(out['ci'][0][0])
t_ci_high25 = float(out['ci'][0][1])
out = rdrandinf(df2[rd_var], df2['dist_to_treated_boundary2023'], reps=reps, level=0.15,
                nwindows=20, wobs=5, obsmin=7, wasymmetric=True, covariates=balance_covs, ci=ci_vec)
t_ate_data = float(out['obs.stat'][0])
t_ci_low_data = float(out['ci'][0][0])
t_ci_high_data = float(out['ci'][0][1])


for share in shares:
    df2['vote_share_pis_adj2023'] = (df2['votes_pis2023'] - share * df2['nonregistered_voters2023']) / (
                df2['votes_valid2023'] - df2['nonregistered_voters2023'])
    df2.loc[df2['vote_share_pis_adj2023'] < 0, 'vote_share_pis_adj2023'] = 0
    df2.loc[df2['vote_share_pis_adj2023'] > 1, 'vote_share_pis_adj2023'] = 1

    df2['vote_share_pis_adj2019'] = (df2['votes_pis2019'] - share * df2['nonregistered_voters2019']) / (
                df2['votes_valid2019'] - df2['nonregistered_voters2019'])
    df2.loc[df2['vote_share_pis_adj2019'] < 0, 'vote_share_pis_adj2019'] = 0
    df2.loc[df2['vote_share_pis_adj2019'] > 1, 'vote_share_pis_adj2019'] = 1

    df2['diff_vote_share_pis_adj'] = df2['vote_share_pis_adj2023'] - df2['vote_share_pis_adj2019']
    df2.loc[df2['Year'] == 2019, 'diff_vote_share_pis_adj'] = np.nan

    rd_var = 'diff_vote_share_pis_adj'

    share_nonres_pis.append(float(share))

    out = rdrandinf(df2[rd_var], df2['dist_to_treated_boundary2023'], wl=-15, wr=15, reps=reps, ci=ci_vec)

    adj_ate15.append(float(out['obs.stat'][0]))
    adj_ci_low15.append(float(out['ci'][0][0]))
    adj_ci_high15.append(float(out['ci'][0][1]))

    out2 = rdrandinf(df2[rd_var], df2['dist_to_treated_boundary2023'], wl=-20, wr=20, reps=reps, ci=ci_vec)

    adj_ate20.append(float(out2['obs.stat'][0]))
    adj_ci_low20.append(float(out2['ci'][0][0]))
    adj_ci_high20.append(float(out2['ci'][0][1]))

    out3 = rdrandinf(df2[rd_var], df2['dist_to_treated_boundary2023'], wl=-25, wr=25, reps=reps, ci=ci_vec)

    adj_ate25.append(float(out3['obs.stat'][0]))
    adj_ci_low25.append(float(out3['ci'][0][0]))
    adj_ci_high25.append(float(out3['ci'][0][1]))

    out4 = rdrandinf(df2[rd_var], df2['dist_to_treated_boundary2023'], reps=reps, level=0.15, nwindows=20, wobs=5, obsmin=7, wasymmetric=True, covariates=balance_covs, ci=ci_vec)

    adj_ate_data.append(float(out4['obs.stat'][0]))
    adj_ci_low_data.append(float(out4['ci'][0][0]))
    adj_ci_high_data.append(float(out4['ci'][0][1]))


ate15 = [t_ate15 for i in np.arange(0, len(adj_ate15), 1)]
ate20 = [t_ate20 for i in np.arange(0, len(adj_ate20), 1)]
ate25 = [t_ate25 for i in np.arange(0, len(adj_ate25), 1)]
ate_data = [t_ate_data for i in np.arange(0, len(adj_ate_data), 1)]
ci_low15 = [t_ci_low15 for i in np.arange(0, len(adj_ci_low15), 1)]
ci_low20 = [t_ci_low20 for i in np.arange(0, len(adj_ci_low20), 1)]
ci_low25 = [t_ci_low25 for i in np.arange(0, len(adj_ci_low25), 1)]
ci_low_data = [t_ci_low_data for i in np.arange(0, len(adj_ci_low_data), 1)]
ci_high15 = [t_ci_high15 for i in np.arange(0, len(adj_ci_high15), 1)]
ci_high20 = [t_ci_high20 for i in np.arange(0, len(adj_ci_high20), 1)]
ci_high25 = [t_ci_high25 for i in np.arange(0, len(adj_ci_high25), 1)]
ci_high_data = [t_ci_high_data for i in np.arange(0, len(adj_ci_high_data), 1)]

sensitivity_df = pd.DataFrame(list(zip(adj_ate15, adj_ate20, adj_ate25, adj_ate_data, ate15, ate20, ate25, ate_data, share_nonres_pis, adj_ci_low15, adj_ci_low20, adj_ci_low25, adj_ci_low_data, adj_ci_high15, adj_ci_high20, adj_ci_high25, adj_ci_high_data, ci_low15, ci_low20, ci_low25, ci_low_data, ci_high15, ci_high20, ci_high25, ci_high_data)), columns=['adj_ate15', 'adj_ate20', 'adj_ate25', 'adj_ate_data', 'ate15', 'ate20', 'ate25', 'ate_data', 'share_nonres_pis', 'adj_ci_low15', 'adj_ci_low20', 'adj_ci_low25', 'adj_ci_low_data', 'adj_ci_high15', 'adj_ci_high20', 'adj_ci_high25', 'adj_ci_high_data', 'ci_low15', 'ci_low20', 'ci_low25', 'ci_low_data', 'ci_high15', 'ci_high20', 'ci_high25', 'ci_high_data'])


f = Frame.create('sensitivity_analysis')
Frame.changeToCWF(f)
f.setObsTotal(len(sensitivity_df))
colnames = sensitivity_df.columns

for i in range(len(colnames)):
    dtype = sensitivity_df.dtypes[i].name
    varname = SFIToolkit.makeVarName(colnames[i])
    varval = sensitivity_df[colnames[i]].values.tolist()
    if dtype == "int64":
        Data.addVarInt(varname)
        Data.store(varname, None, varval)
    elif dtype == "float64":
        Data.addVarDouble(varname)
        Data.store(varname, None, varval)
    elif dtype == "bool":
        Data.addVarByte(varname)
        Data.store(varname, None, varval)
    else:
        Data.addVarStr(varname, 1)
        s = [str(i) for i in varval] 
        Data.store(varname, None, s)

end


label var share_nonres_pis "Share of Non-Resident Voters Assumed to Vote for PiS"

twoway  (lfit adj_ate15 share_nonres_pis, sort lcolor(black)) (line ate15 share_nonres_pis, lcolor(red) lpattern(dash)) (rarea adj_ci_low15 adj_ci_high15 share_nonres_pis, sort fcolor(gray%10)) , legend(off) yline(0, lcolor(black) lpattern(dash) noextend) ytitle(Adjusted ATE, margin(small) size(large)) xtitle(, size(large) margin(medium)) xlabel(, labsize(large)) ylabel(, labsize(large)) name(adj15, replace)

twoway  (lfit adj_ate20 share_nonres_pis, sort lcolor(black)) (line ate20 share_nonres_pis, lcolor(red) lpattern(dash)) (rarea adj_ci_low20 adj_ci_high20 share_nonres_pis, sort fcolor(gray%10)) , legend(off) yline(0, lcolor(black) lpattern(dash) noextend) ytitle(Adjusted ATE, margin(small) size(large)) xtitle(, size(large) margin(medium)) xlabel(, labsize(large)) ylabel(, labsize(large)) name(adj20, replace)

twoway  (lfit adj_ate25 share_nonres_pis, sort lcolor(black)) (line ate25 share_nonres_pis, lcolor(red) lpattern(dash)) (rarea adj_ci_low25 adj_ci_high25 share_nonres_pis, sort fcolor(gray%10)) , legend(off) yline(0, lcolor(black) lpattern(dash) noextend) ytitle(Adjusted ATE, margin(small) size(large)) xtitle(, size(large) margin(medium)) xlabel(, labsize(large)) ylabel(, labsize(large)) name(adj25, replace)

twoway  (lfit adj_ate_data share_nonres_pis, sort lcolor(black)) (line ate_data share_nonres_pis, lcolor(red) lpattern(dash)) (rarea adj_ci_low_data adj_ci_high_data share_nonres_pis, sort fcolor(gray%10)) , legend(off) yline(0, lcolor(black) lpattern(dash) noextend) ytitle(Adjusted ATE, margin(small) size(large)) xtitle(, size(large) margin(medium)) xlabel(, labsize(large)) ylabel(, labsize(large)) name(adj_data, replace)

* Export coeffiicient plots as .jpg
capture mkdir "Figures"
graph export "Figures\Figure_B1_a.jpg", as(jpg) name("adj_data") fontface("LM Roman 10") replace
graph export "Figures\Figure_B1_b.jpg", as(jpg) name("adj15") fontface("LM Roman 10") replace
graph export "Figures\Figure_B1_c.jpg", as(jpg) name("adj20") fontface("LM Roman 10") replace
graph export "Figures\Figure_B1_d.jpg", as(jpg) name("adj25") fontface("LM Roman 10") replace

***********************************
***********************************
***********************************



***********************************
**# Table B.8: Comparison of Pre-treatment Means by Treatment Group: Include Partially Treated
***********************************

frame change data2019

local vars population voters constituency_urban turnout vote_share_pis vote_share_left_oppo vote_share_right_oppo lat lon
local if "if abs(dist_to_treated_boundary) <30 & partial_treated == 0"
local if2 "if abs(dist_to_treated_boundary)<30 & !(treated == 1 & partial_treated == 0)"
local if3 "if abs(dist_to_treated_boundary)<30 & treated == 1"

* Generate no. of obs
tab treated `if', matcell(treatfreq)
matrix treatfreq=treatfreq\r(N)
tab treated `if2', matcell(treatfreq2)
matrix treatfreq2=treatfreq2\r(N)
local obs_con = treatfreq[1,1]
local obs_tre = treatfreq[2,1]
local obs_tre2 = treatfreq2[2,1]

* Generate a simple covariate table
foreach var of varlist `vars' {
	** Run a regression for groups and Store the means for each group --- exclude partially treated
	reg `var' treated `if', robust
	global m`var'_0: di %10.2fc _b[_cons]
	global m`var'_1: di %10.2fc _b[_cons] + _b[treated]
	
	** CONTROL VS. PARTIALLY TREATED
	reg `var' treated `if2', robust
	global dif_`var': di %10.2fc _b[treated]

	summ `var' if partial_treated2019 == 1 & abs(dist_to_treated_boundary)<30
	global m`var'_11: di %10.2fc r(mean)

	** Store the p-value 
	qui test treated=0
	global p1_`var': di %3.2fc r(p)
	
	** TREATED VS. PARTIALLY TREATED
	reg `var' partial_treated `if3', robust
	global dif2_`var': di %10.2fc _b[partial_treated]

	** Store the p-value 
	qui test partial_treated=0
	global p2_`var': di %3.2fc r(p)
	
	** Store the label of the variable
	global lbe_`var' : var label `var'
}

* Generating table

capture mkdir "Tables"

texdoc init "Tables/Table_B8.tex", replace force
tex \begin{table}[htbp]\centering\small
tex \setlength\tabcolsep{0pt}
tex \caption{Summary of Pre-Treatment Means in 2019 by Treatment Status}
tex \label{table:summary:means:partially:treated}
tex \begin{tabularx}{1.0\hsize}{l *{5}{Y}}
tex \toprule
tex   &        Control  &      Treatment  & Partially Treated & Partially Treated vs. Control & Partially Treated vs. Treated\\
tex \cmidrule(lr){2-4} \cmidrule(lr){5-6}    &        N=`obs_con' &   N=`obs_tre'  & N=`obs_tre2' &     \\
tex \midrule
foreach var of varlist `vars' {
	tex ${lbe_`var'} &  ${m`var'_0} & ${m`var'_1} & ${m`var'_11} & ${dif_`var'} & ${dif2_`var'}   \\
	tex  &   &  &  & (${p1_`var'}) & (${p2_`var'}) \\

}
tex \bottomrule
tex \multicolumn{6}{p{\linewidth}}{\footnotesize \emph{Notes}: Table reports mean variable values by group (Columns 1-3). Control group includes all untreated polling stations within 30 kilometers from the state of emergency boundary. Columns 4 and 5 report differences and p-values from a t-test comparing variable means of the partially treated polling stations with the control and treatment groups, respectively.}\\
tex \end{tabularx}
tex \end{table}
texdoc close

***********************************
***********************************
***********************************



***********************************
**# Table B.9: Pre-Treatment Balance when including Partially Treated --- Code Partially Treated as Treated
***********************************

frame change data2015_2019

* Re-Define labels
label var diff_vote_share_pis "$\Delta$ PiS Vote Share (2015-2019)"
label var diff_vote_share_left_oppo "$\Delta$ Left Opposition Vote Share (2015-2019)"
label var diff_vote_share_right_oppo "$\Delta$ Right Opposition Vote Share (2015-2019)"
label var diff_turnout "$\Delta$ Turnout (2015-2019)"
label var population "Population (2019)"
label var voters "Registered Voters (2019)"
label var constituency_urban "Urban Constituency (Yes=1) (2019)"

* Conduct inference and generate confidence intervals

** Define macros
global vars diff_vote_share_pis diff_vote_share_left_oppo diff_vote_share_right_oppo diff_turnout population voters constituency_urban
global balance_covs diff_vote_share_pis diff_vote_share_left_oppo diff_vote_share_right_oppo diff_turnout

** Run randomization inference
foreach var of varlist $vars {
	
	rdrandinf `var' dist_to_treated_boundary2019 if Year == 2019, reps($reps) dropmissing d(0.05) wl(-15) wr(15) fuzzy(treated tsls) ci(0.05)
	
	if int(r(obs_stat)) == 0 {
		global l1_`var': di %9.3f r(obs_stat)
		global cil1_`var': di %9.3f r(CI)[1,1]
		global cir1_`var': di %9.3f r(CI)[1,2]
	} 
	else {
		global l1_`var': di %9.1f r(obs_stat) 
		global cil1_`var': di %9.1f r(CI)[1,1] 
		global cir1_`var': di %9.1f r(CI)[1,2] 
	}
	global p1_`var': di %9.2f r(asy_pval) 
	global wl1_`var': di %9.0f r(wl) 
	global wr1_`var': di %9.0f r(wr) 
	global nl1_`var': di %9.0f r(N_left) 
	global nr1_`var': di %9.0f r(N_right)


	rdrandinf `var' dist_to_treated_boundary2019 if Year == 2019, reps($reps) dropmissing d(0.05) wl(-20) wr(20) fuzzy(treated tsls) ci(0.05)
	
	if int(r(obs_stat)) == 0 {
		global l2_`var': di %9.3f r(obs_stat) 
		global cil2_`var': di %9.3f r(CI)[1,1]
		global cir2_`var': di %9.3f r(CI)[1,2]
	} 
	else {
		global l2_`var': di %9.1f r(obs_stat) 
		global cil2_`var': di %9.1f r(CI)[1,1]
		global cir2_`var': di %9.1f r(CI)[1,2]
	}
	global p2_`var': di %9.2f r(asy_pval)
	global wl2_`var': di %9.0f r(wl)
	global wr2_`var': di %9.0f r(wr)
	global nl2_`var': di %9.0f r(N_left)
	global nr2_`var': di %9.0f r(N_right)


	rdrandinf `var' dist_to_treated_boundary2019 if Year == 2019, reps($reps) dropmissing d(0.05) wl(-25) wr(25) fuzzy(treated tsls) ci(0.05)
	
	if int(r(obs_stat)) == 0 {
		global l3_`var': di %9.3f r(obs_stat) 
		global cil3_`var': di %9.3f r(CI)[1,1] 
		global cir3_`var': di %9.3f r(CI)[1,2] 
	} 
	else {
		global l3_`var': di %9.1f r(obs_stat) 
		global cil3_`var': di %9.1f r(CI)[1,1]
		global cir3_`var': di %9.1f r(CI)[1,2] 
	}
	global p3_`var': di %9.2f r(asy_pval) 
	global wl3_`var': di %9.0f r(wl)
	global wr3_`var': di %9.0f r(wr) 
	global nl3_`var': di %9.0f r(N_left)
	global nr3_`var': di %9.0f r(N_right)


	rdrandinf `var' dist_to_treated_boundary2019 if Year == 2019, reps($reps) dropmissing level(0.15) covariates($balance_covs) wmin(1) wobs(5) nw(20) qui wasymm fuzzy(treated tsls) ci(0.05)
	
	if int(r(obs_stat)) == 0 {
		global l4_`var': di %9.3f r(obs_stat) 
		global cil4_`var': di %9.3f r(CI)[1,1]
		global cir4_`var': di %9.3f r(CI)[1,2] 
	} 
	else {
		global l4_`var': di %9.1f r(obs_stat) 
		global cil4_`var': di %9.1f r(CI)[1,1]
		global cir4_`var': di %9.1f r(CI)[1,2] 
	}	
	global p4_`var': di %9.2f r(asy_pval)
	global wl4_`var': di %9.2f r(wl) 
	global wr4_`var': di %9.2f r(wr) 
	global nl4_`var': di %9.0f r(N_left)
	global nr4_`var': di %9.0f r(N_right)

	** Store the label of the variable
	global lbe_`var' : var label `var'
}

* Generating table
capture mkdir "Tables"
local vars diff_vote_share_pis diff_vote_share_left_oppo diff_vote_share_right_oppo diff_turnout population voters constituency_urban
local ascii_code 65
texdoc init "Tables/Table_B9.tex", replace force
tex \begin{table}[htbp]
tex \small
tex \caption{Pre-treatment Balance Test --- Including Partially Treated as Treated}
tex \setlength\tabcolsep{0pt}
tex \vspace{-15pt}
tex \label{table:pretreatment:balance:test:incl:part:treated:tr}
tex \begin{tabularx}{1.0\hsize}{l *{4}{Y}}
tex \toprule
tex & \multicolumn{3}{c}{Manual Windows} & \multicolumn{1}{c}{Data-driven} \\
tex \cmidrule(lr){2-4} \cmidrule(lr){5-5}
tex & \([$wl1_diff_vote_share_pis, $wr1_diff_vote_share_pis]\) & \([$wl2_diff_vote_share_pis, $wr2_diff_vote_share_pis]\) & \([$wl3_diff_vote_share_pis, $wr3_diff_vote_share_pis]\) & \([$wl4_diff_vote_share_pis,$wr4_diff_vote_share_pis]\) \\
tex \midrule
foreach var of varlist `vars' {
	local panel_letter = char(`ascii_code')
	tex \multicolumn{5}{l}{\textbf{Panel `panel_letter'. ${lbe_`var'}}} \\
	tex \midrule
    tex LATE & ${l1_`var'} & ${l2_`var'} & ${l3_`var'} & ${l4_`var'} \\
    tex P-value & ${p1_`var'} & ${p2_`var'} & ${p3_`var'} & ${p4_`var'} \\
    tex 95\% CI & [${cil1_`var'}, ${cir1_`var'}] & [${cil2_`var'}, ${cir2_`var'}] & [${cil3_`var'}, ${cir3_`var'}] & [${cil4_`var'}, ${cir4_`var'}] \\
	tex \midrule
	local ++ascii_code
}
tex N$+$ & ${nr1_diff_vote_share_pis} & ${nr2_diff_vote_share_pis} & ${nr3_diff_vote_share_pis} & ${nr4_diff_vote_share_pis} \\
tex N$-$ & ${nl1_diff_vote_share_pis} & ${nl2_diff_vote_share_pis} & ${nl3_diff_vote_share_pis} & ${nl4_diff_vote_share_pis} \\
tex \bottomrule
tex \multicolumn{5}{p{\linewidth}}{\scriptsize \emph{Notes}: Table presents results of a pre-treatment balance test when partially treated polling stations are included as treated observations. Results are obtained using the Stata implementation of \emph{rdrandinf} by \citet{cattaneo_titiunik_vazquez_bare2016}. LATE point estimates reflect the two-stage least squares estimates of the unadjusted difference in means between treatment and control groups using a uniform kernel. P-values and 95\% confidence intervals are based on asymptotic approximations. Data-driven window is selected using the \emph{rdwinselect} command by \citet{cattaneo_titiunik_vazquez_bare2016} and reflects the largest window around the cutoff such that the minimum p-value on the balance test across the four first-differenced outcome variables is larger than 0.15.}\\
tex \end{tabularx}
tex \end{table}
texdoc close

***********************************
***********************************
***********************************



***********************************
**# Table B.10: Pre-Treatment Balance when including Partially Treated --- Code Partially Treated as Control
***********************************

frame change data2015_2019

preserve
replace treated2019 = 0 if partial_treated2019 == 1

* Re-Define labels
label var diff_vote_share_pis "$\Delta$ PiS Vote Share (2015-2019)"
label var diff_vote_share_left_oppo "$\Delta$ Left Opposition Vote Share (2015-2019)"
label var diff_vote_share_right_oppo "$\Delta$ Right Opposition Vote Share (2015-2019)"
label var diff_turnout "$\Delta$ Turnout (2015-2019)"
label var population "Population (2019)"
label var voters "Registered Voters (2019)"
label var constituency_urban "Urban Constituency (Yes=1) (2019)"

* Conduct inference and generate confidence intervals

** Define macros
global vars diff_vote_share_pis diff_vote_share_left_oppo diff_vote_share_right_oppo diff_turnout population voters constituency_urban
global balance_covs diff_vote_share_pis diff_vote_share_left_oppo diff_vote_share_right_oppo diff_turnout

** Run randomization inference

foreach var of varlist $vars {
	
	rdrandinf `var' dist_to_treated_boundary2019 if Year == 2019, reps($reps) dropmissing d(0.05) wl(-15) wr(15) fuzzy(treated tsls) ci(0.05)
	
	if int(r(obs_stat)) == 0 {
		global l1_`var': di %9.3f r(obs_stat)
		global cil1_`var': di %9.3f r(CI)[1,1]
		global cir1_`var': di %9.3f r(CI)[1,2] 
	} 
	else {
		global l1_`var': di %9.1f r(obs_stat) 
		global cil1_`var': di %9.1f r(CI)[1,1] 
		global cir1_`var': di %9.1f r(CI)[1,2] 
	}
	global p1_`var': di %9.2f r(asy_pval) 
	global wl1_`var': di %9.0f r(wl) 
	global wr1_`var': di %9.0f r(wr)
	global nl1_`var': di %9.0f r(N_left) 
	global nr1_`var': di %9.0f r(N_right) 

	rdrandinf `var' dist_to_treated_boundary2019 if Year == 2019, reps($reps) dropmissing d(0.05) wl(-20) wr(20) fuzzy(treated tsls) ci(0.05)
	
	if int(r(obs_stat)) == 0 {
		global l2_`var': di %9.3f r(obs_stat)
		global cil2_`var': di %9.3f r(CI)[1,1] 
		global cir2_`var': di %9.3f r(CI)[1,2]
	} 
	else {
		global l2_`var': di %9.1f r(obs_stat) 
		global cil2_`var': di %9.1f r(CI)[1,1] 
		global cir2_`var': di %9.1f r(CI)[1,2] 
	}
	global p2_`var': di %9.2f r(asy_pval)
	global wl2_`var': di %9.0f r(wl)
	global wr2_`var': di %9.0f r(wr) 
	global nl2_`var': di %9.0f r(N_left)
	global nr2_`var': di %9.0f r(N_right)

	rdrandinf `var' dist_to_treated_boundary2019 if Year == 2019, reps($reps) dropmissing d(0.05) wl(-25) wr(25) fuzzy(treated tsls) ci(0.05)
	
	if int(r(obs_stat)) == 0 {
		global l3_`var': di %9.3f r(obs_stat) 
		global cil3_`var': di %9.3f r(CI)[1,1] 
		global cir3_`var': di %9.3f r(CI)[1,2] 
	} 
	else {
		global l3_`var': di %9.1f r(obs_stat)
		global cil3_`var': di %9.1f r(CI)[1,1]
		global cir3_`var': di %9.1f r(CI)[1,2] 
	}
	global p3_`var': di %9.2f r(asy_pval) 
	global wl3_`var': di %9.0f r(wl)
	global wr3_`var': di %9.0f r(wr) 
	global nl3_`var': di %9.0f r(N_left) 
	global nr3_`var': di %9.0f r(N_right)

	rdrandinf `var' dist_to_treated_boundary2019 if Year == 2019, reps($reps) dropmissing level(0.15) covariates($balance_covs) wmin(1) wobs(5) nw(20) qui wasymm fuzzy(treated tsls) ci(0.05)
	
	if int(r(obs_stat)) == 0 {
		global l14`var': di %9.3f r(obs_stat) 
		global cil4_`var': di %9.3f r(CI)[1,1] 
		global cir4_`var': di %9.3f r(CI)[1,2] 
	} 
	else {
		global l4_`var': di %9.1f r(obs_stat) 
		global cil4_`var': di %9.1f r(CI)[1,1] 
		global cir4_`var': di %9.1f r(CI)[1,2] 
	}	
	global p4_`var': di %9.2f r(asy_pval) 
	global wl4_`var': di %9.2f r(wl) 
	global wr4_`var': di %9.2f r(wr) 
	global nl4_`var': di %9.0f r(N_left) 
	global nr4_`var': di %9.0f r(N_right)
	
	** Store the label of the variable
	global lbe_`var' : var label `var'
}

restore

* Generating table
capture mkdir "Tables"
local vars diff_vote_share_pis diff_vote_share_left_oppo diff_vote_share_right_oppo diff_turnout population voters constituency_urban
local ascii_code 65
texdoc init "Tables/Table_B10.tex", replace force
tex \begin{table}[htbp]
tex \small
tex \caption{Pre-treatment Balance Test --- Including Partially Treated as Control}
tex \setlength\tabcolsep{0pt}
tex \vspace{-15pt}
tex \label{table:pretreatment:balance:test:incl:part:treated:contr}
tex \begin{tabularx}{1.0\hsize}{l *{4}{Y}}
tex \toprule
tex & \multicolumn{3}{c}{Manual Windows} & \multicolumn{1}{c}{Data-driven} \\
tex \cmidrule(lr){2-4} \cmidrule(lr){5-5}
tex & \([$wl1_diff_vote_share_pis, $wr1_diff_vote_share_pis]\) & \([$wl2_diff_vote_share_pis, $wr2_diff_vote_share_pis]\) & \([$wl3_diff_vote_share_pis, $wr3_diff_vote_share_pis]\) & \([$wl4_diff_vote_share_pis,$wr4_diff_vote_share_pis]\) \\
tex \midrule
foreach var of varlist `vars' {
	local panel_letter = char(`ascii_code')
	tex \multicolumn{5}{l}{\textbf{Panel `panel_letter'. ${lbe_`var'}}} \\
	tex \midrule
    tex LATE & ${l1_`var'} & ${l2_`var'} & ${l3_`var'} & ${l4_`var'} \\
    tex P-value & ${p1_`var'} & ${p2_`var'} & ${p3_`var'} & ${p4_`var'} \\
    tex 95\% CI & [${cil1_`var'}, ${cir1_`var'}] & [${cil2_`var'}, ${cir2_`var'}] & [${cil3_`var'}, ${cir3_`var'}] & [${cil4_`var'}, ${cir4_`var'}] \\
	tex \midrule
	local ++ascii_code
}
tex N$+$ & ${nr1_diff_vote_share_pis} & ${nr2_diff_vote_share_pis} & ${nr3_diff_vote_share_pis} & ${nr4_diff_vote_share_pis} \\
tex N$-$ & ${nl1_diff_vote_share_pis} & ${nl2_diff_vote_share_pis} & ${nl3_diff_vote_share_pis} & ${nl4_diff_vote_share_pis} \\
tex \bottomrule
tex \multicolumn{5}{p{\linewidth}}{\scriptsize \emph{Notes}: Table presents results of a pre-treatment balance test when partially treated polling stations are included as control observations. Results are obtained using the Stata implementation of \emph{rdrandinf} by \citet{cattaneo_titiunik_vazquez_bare2016}. LATE point estimates reflect the two-stage least squares estimates of the unadjusted difference in means between treatment and control groups using a uniform kernel. P-values and 95\% confidence intervals are based on asymptotic approximations. Data-driven window is selected using the \emph{rdwinselect} command by \citet{cattaneo_titiunik_vazquez_bare2016} and reflects the largest window around the cutoff such that the minimum p-value on the balance test across the four first-differenced outcome variables is larger than 0.15.}\\
tex \end{tabularx}
tex \end{table}
texdoc close

***********************************
***********************************
***********************************



***********************************
**# Table B.11: Results when including Partially Treated --- Code Partially Treated as Treated
***********************************

frame change data2019_2023

* Conduct inference and generate confidence intervals

** Define macros
global vars diff_vote_share_pis diff_vote_share_left_oppo diff_vote_share_right_oppo diff_turnout
global balance_covs diff_vote_share_pis diff_vote_share_left_oppo diff_vote_share_right_oppo diff_turnout

** Run randomization inference
foreach var of varlist $vars {
	
	rdrandinf `var' dist_to_treated_boundary2023 if Year == 2023, reps($reps) dropmissing d(0.05) wl(-15) wr(15) fuzzy(treated tsls) ci(0.05)
	
	if int(r(obs_stat)) == 0 {
		global l1_`var': di %9.3f r(obs_stat) 
		global cil1_`var': di %9.3f r(CI)[1,1] 
		global cir1_`var': di %9.3f r(CI)[1,2] 
	} 
	else {
		global l1_`var': di %9.1f r(obs_stat) 
		global cil1_`var': di %9.1f r(CI)[1,1] 
		global cir1_`var': di %9.1f r(CI)[1,2] 
	}
	global p1_`var': di %9.2f r(asy_pval) 
	global wl1_`var': di %9.0f r(wl)
	global wr1_`var': di %9.0f r(wr) 
	global nl1_`var': di %9.0f r(N_left)
	global nr1_`var': di %9.0f r(N_right)

	rdrandinf `var' dist_to_treated_boundary2023 if Year == 2023, reps($reps) dropmissing d(0.05) wl(-20) wr(20) fuzzy(treated tsls) ci(0.05)
	
	if int(r(obs_stat)) == 0 {
		global l2_`var': di %9.3f r(obs_stat) 
		global cil2_`var': di %9.3f r(CI)[1,1]
		global cir2_`var': di %9.3f r(CI)[1,2] 
	} 
	else {
		global l2_`var': di %9.1f r(obs_stat)
		global cil2_`var': di %9.1f r(CI)[1,1] 
		global cir2_`var': di %9.1f r(CI)[1,2] 
	}
	global p2_`var': di %9.2f r(asy_pval)
	global wl2_`var': di %9.0f r(wl)
	global wr2_`var': di %9.0f r(wr) 
	global nl2_`var': di %9.0f r(N_left) 
	global nr2_`var': di %9.0f r(N_right)

	rdrandinf `var' dist_to_treated_boundary2023 if Year == 2023, reps($reps) dropmissing d(0.05) wl(-25) wr(25) fuzzy(treated tsls) ci(0.05)
	
	if int(r(obs_stat)) == 0 {
		global l3_`var': di %9.3f r(obs_stat)
		global cil3_`var': di %9.3f r(CI)[1,1]
		global cir3_`var': di %9.3f r(CI)[1,2] 
	} 
	else {
		global l3_`var': di %9.1f r(obs_stat) 
		global cil3_`var': di %9.1f r(CI)[1,1] 
		global cir3_`var': di %9.1f r(CI)[1,2] 
	}
	global p3_`var': di %9.2f r(asy_pval)
	global wl3_`var': di %9.0f r(wl) 
	global wr3_`var': di %9.0f r(wr)
	global nl3_`var': di %9.0f r(N_left) 
	global nr3_`var': di %9.0f r(N_right)

	rdrandinf `var' dist_to_treated_boundary2023 if Year == 2023, reps($reps) dropmissing level(0.15) covariates($balance_covs) wmin(1) wobs(5) nw(20) qui wasymm fuzzy(treated tsls) ci(0.05)
	
	if int(r(obs_stat)) == 0 {
		global l4_`var': di %9.3f r(obs_stat) 
		global cil4_`var': di %9.3f r(CI)[1,1] 
		global cir4_`var': di %9.3f r(CI)[1,2]
	} 
	else {
		global l4_`var': di %9.1f r(obs_stat) 
		global cil4_`var': di %9.1f r(CI)[1,1] 
		global cir4_`var': di %9.1f r(CI)[1,2]
	}	
	global p4_`var': di %9.2f r(asy_pval)
	global wl4_`var': di %9.2f r(wl)
	global wr4_`var': di %9.2f r(wr) 
	global nl4_`var': di %9.0f r(N_left) 
	global nr4_`var': di %9.0f r(N_right) 
	
	** Store the label of the variable
	global lbe_`var' : var label `var'
}

* Re-Define labels
label var diff_vote_share_pis "$\Delta$ PiS Vote Share (2019-2023)"
label var diff_vote_share_left_oppo "$\Delta$ Left Opposition Vote Share (2019-2023)"
label var diff_vote_share_right_oppo "$\Delta$ Right Opposition Vote Share (2019-2023)"
label var diff_turnout "$\Delta$ Turnout (2019-2023)"

* Generating table
capture mkdir "Tables"
local vars diff_vote_share_pis diff_vote_share_left_oppo diff_vote_share_right_oppo diff_turnout
local ascii_code 65
texdoc init "Tables/Table_B11.tex", replace force
tex \begin{table}[htbp]
tex \small
tex \caption{Results --- Including Partially Treated as Treated}
tex \vspace{-15pt}
tex \label{table:results:incl:part:treated:tr}
tex \begin{tabularx}{\textwidth}{l *{4}{Y}}
tex \toprule
tex & \multicolumn{3}{c}{Manual Windows} & \multicolumn{1}{c}{Data-driven} \\
tex \cmidrule(lr){2-4} \cmidrule(lr){5-5}
tex & \([$wl1_diff_vote_share_pis, $wr1_diff_vote_share_pis]\) & \([$wl2_diff_vote_share_pis, $wr2_diff_vote_share_pis]\) & \([$wl3_diff_vote_share_pis, $wr3_diff_vote_share_pis]\) & \([$wl4_diff_vote_share_pis,$wr4_diff_vote_share_pis]\) \\
tex \midrule
foreach var of varlist `vars' {
	local panel_letter = char(`ascii_code')
	tex \multicolumn{5}{l}{\textbf{Panel `panel_letter'. ${lbe_`var'}}} \\
	tex \midrule
    tex LATE & ${l1_`var'} & ${l2_`var'} & ${l3_`var'} & ${l4_`var'} \\
    tex P-value & ${p1_`var'} & ${p2_`var'} & ${p3_`var'} & ${p4_`var'} \\
    tex 95\% CI & [${cil1_`var'}, ${cir1_`var'}] & [${cil2_`var'}, ${cir2_`var'}] & [${cil3_`var'}, ${cir3_`var'}] & [${cil4_`var'}, ${cir4_`var'}] \\
	tex \midrule
	local ++ascii_code
}
tex N$+$ & ${nr1_diff_vote_share_pis} & ${nr2_diff_vote_share_pis} & ${nr3_diff_vote_share_pis} & ${nr4_diff_vote_share_pis} \\
tex N$-$ & ${nl1_diff_vote_share_pis} & ${nl2_diff_vote_share_pis} & ${nl3_diff_vote_share_pis} & ${nl4_diff_vote_share_pis} \\
tex \bottomrule
tex \multicolumn{5}{p{\linewidth}}{\footnotesize \emph{Notes}: Table presents main results when partially treated polling stations are included as treated observations. Results are obtained using the Stata implementation of \emph{rdrandinf} by \citet{cattaneo_titiunik_vazquez_bare2016}. LATE point estimates reflect the two-stage least squares estimates of the unadjusted difference in means between treatment and control groups using a uniform kernel. P-values and 95\% confidence intervals are based on asymptotic approximations. Data-driven window is selected using the \emph{rdwinselect} command by \citet{cattaneo_titiunik_vazquez_bare2016} and reflects the largest window around the cutoff such that the minimum p-value on the balance test across the four first-differenced outcome variables is larger than 0.15.}\\
tex \end{tabularx}
tex \end{table}
texdoc close

***********************************
***********************************
***********************************



***********************************
**# Table B.12: Results when including Partially Treated --- Code Partially Treated as Control
***********************************

frame change data2019_2023

preserve
replace treated2019 = 0 if partial_treated2019 == 1

* Conduct inference and generate confidence intervals

** Define macros
global vars diff_vote_share_pis diff_vote_share_left_oppo diff_vote_share_right_oppo diff_turnout
global balance_covs diff_vote_share_pis diff_vote_share_left_oppo diff_vote_share_right_oppo diff_turnout

** Run randomization inference
foreach var of varlist $vars {
	
	rdrandinf `var' dist_to_treated_boundary2023 if Year == 2023, reps($reps) dropmissing d(0.05) wl(-15) wr(15) fuzzy(treated tsls) ci(0.05)
	
	if int(r(obs_stat)) == 0 {
		global l1_`var': di %9.3f r(obs_stat)
		global cil1_`var': di %9.3f r(CI)[1,1]
		global cir1_`var': di %9.3f r(CI)[1,2]
	} 
	else {
		global l1_`var': di %9.1f r(obs_stat)
		global cil1_`var': di %9.1f r(CI)[1,1]
		global cir1_`var': di %9.1f r(CI)[1,2]
	}
	global p1_`var': di %9.2f r(asy_pval) 
	global wl1_`var': di %9.0f r(wl) 
	global wr1_`var': di %9.0f r(wr) 
	global nl1_`var': di %9.0f r(N_left) 
	global nr1_`var': di %9.0f r(N_right)

	rdrandinf `var' dist_to_treated_boundary2023 if Year == 2023, reps($reps) dropmissing d(0.05) wl(-20) wr(20) fuzzy(treated tsls) ci(0.05)
	
	if int(r(obs_stat)) == 0 {
		global l2_`var': di %9.3f r(obs_stat)
		global cil2_`var': di %9.3f r(CI)[1,1]
		global cir2_`var': di %9.3f r(CI)[1,2]
	} 
	else {
		global l2_`var': di %9.1f r(obs_stat) 
		global cil2_`var': di %9.1f r(CI)[1,1]
		global cir2_`var': di %9.1f r(CI)[1,2] 
	}
	global p2_`var': di %9.2f r(asy_pval) 
	global wl2_`var': di %9.0f r(wl)
	global wr2_`var': di %9.0f r(wr)
	global nl2_`var': di %9.0f r(N_left)
	global nr2_`var': di %9.0f r(N_right) 

	rdrandinf `var' dist_to_treated_boundary2023 if Year == 2023, reps($reps) dropmissing d(0.05) wl(-25) wr(25) fuzzy(treated tsls) ci(0.05)
	
	if int(r(obs_stat)) == 0 {
		global l3_`var': di %9.3f r(obs_stat) 
		global cil3_`var': di %9.3f r(CI)[1,1]
		global cir3_`var': di %9.3f r(CI)[1,2] 
	} 
	else {
		global l3_`var': di %9.1f r(obs_stat)
		global cil3_`var': di %9.1f r(CI)[1,1]
		global cir3_`var': di %9.1f r(CI)[1,2] 
	}
	global p3_`var': di %9.2f r(asy_pval) 
	global wl3_`var': di %9.0f r(wl) 
	global wr3_`var': di %9.0f r(wr)
	global nl3_`var': di %9.0f r(N_left)
	global nr3_`var': di %9.0f r(N_right)

	rdrandinf `var' dist_to_treated_boundary2023 if Year == 2023, reps($reps) dropmissing level(0.15) covariates($balance_covs) wmin(1) wobs(5) nw(20) qui wasymm fuzzy(treated tsls) ci(0.05)
	
	if int(r(obs_stat)) == 0 {
		global l4_`var': di %9.3f r(obs_stat)
		global cil4_`var': di %9.3f r(CI)[1,1]
		global cir4_`var': di %9.3f r(CI)[1,2]
	} 
	else {
		global l4_`var': di %9.1f r(obs_stat)
		global cil4_`var': di %9.1f r(CI)[1,1]
		global cir4_`var': di %9.1f r(CI)[1,2]
	}	
	global p4_`var': di %9.2f r(asy_pval) 
	global wl4_`var': di %9.2f r(wl)
	global wr4_`var': di %9.2f r(wr)
	global nl4_`var': di %9.0f r(N_left)
	global nr4_`var': di %9.0f r(N_right) 
	
	** Store the label of the variable
	global lbe_`var' : var label `var'
}

restore

* Re-Define labels
label var diff_vote_share_pis "$\Delta$ PiS Vote Share (2019-2023)"
label var diff_vote_share_left_oppo "$\Delta$ Left Opposition Vote Share (2019-2023)"
label var diff_vote_share_right_oppo "$\Delta$ Right Opposition Vote Share (2019-2023)"
label var diff_turnout "$\Delta$ Turnout (2019-2023)"

* Generating table
capture mkdir "Tables"
local vars diff_vote_share_pis diff_vote_share_left_oppo diff_vote_share_right_oppo diff_turnout
local ascii_code 65
texdoc init "Tables/Table_B12.tex", replace force
tex \begin{table}[htbp]
tex \small
tex \caption{Results --- Including Partially Treated as Control}
tex \vspace{-15pt}
tex \label{table:results:incl:part:treated:contr}
tex \begin{tabularx}{\textwidth}{l *{4}{Y}}
tex \toprule
tex & \multicolumn{3}{c}{Manual Windows} & \multicolumn{1}{c}{Data-driven} \\
tex \cmidrule(lr){2-4} \cmidrule(lr){5-5}
tex & \([$wl1_diff_vote_share_pis, $wr1_diff_vote_share_pis]\) & \([$wl2_diff_vote_share_pis, $wr2_diff_vote_share_pis]\) & \([$wl3_diff_vote_share_pis, $wr3_diff_vote_share_pis]\) & \([$wl4_diff_vote_share_pis,$wr4_diff_vote_share_pis]\) \\
tex \midrule
foreach var of varlist `vars' {
	local panel_letter = char(`ascii_code')
	tex \multicolumn{5}{l}{\textbf{Panel `panel_letter'. ${lbe_`var'}}} \\
	tex \midrule
    tex LATE & ${l1_`var'} & ${l2_`var'} & ${l3_`var'} & ${l4_`var'} \\
    tex P-value & ${p1_`var'} & ${p2_`var'} & ${p3_`var'} & ${p4_`var'} \\
    tex 95\% CI & [${cil1_`var'}, ${cir1_`var'}] & [${cil2_`var'}, ${cir2_`var'}] & [${cil3_`var'}, ${cir3_`var'}] & [${cil4_`var'}, ${cir4_`var'}] \\
	tex \midrule
	local ++ascii_code
}
tex N$+$ & ${nr1_diff_vote_share_pis} & ${nr2_diff_vote_share_pis} & ${nr3_diff_vote_share_pis} & ${nr4_diff_vote_share_pis} \\
tex N$-$ & ${nl1_diff_vote_share_pis} & ${nl2_diff_vote_share_pis} & ${nl3_diff_vote_share_pis} & ${nl4_diff_vote_share_pis} \\
tex \bottomrule
tex \multicolumn{5}{p{\linewidth}}{\footnotesize \emph{Notes}: Table presents main results when partially treated polling stations are included as control observations. Results are obtained using the Stata implementation of \emph{rdrandinf} by \citet{cattaneo_titiunik_vazquez_bare2016}. LATE point estimates reflect the two-stage least squares estimates of the unadjusted difference in means between treatment and control groups using a uniform kernel. P-values and 95\% confidence intervals are based on asymptotic approximations. Data-driven window is selected using the \emph{rdwinselect} command by \citet{cattaneo_titiunik_vazquez_bare2016} and reflects the largest window around the cutoff such that the minimum p-value on the balance test across the four first-differenced outcome variables is larger than 0.15.}\\
tex \end{tabularx}
tex \end{table}
texdoc close

***********************************
***********************************
***********************************



***********************************
**# Table B.13 : Balancing 2015-2019 Using Continuity Framework
***********************************

frame change data2015_2019

local covs = ""
local if = "if partial_treated == 0"
local opts = "kernel(triangular) p(0)"

local i = 1
foreach bw in 15 20 25 {
	qui eststo rd201519_1_`i': rdrobust diff_vote_share_pis dist_to_treated_boundary `if', c(0) `opts' covs(`covs') h(`bw' `bw')
	qui eststo rd201519_2_`i':rdrobust diff_vote_share_left_oppo dist_to_treated_boundary `if', c(0) `opts' covs(`covs') h(`bw' `bw')
	qui eststo rd201519_3_`i':rdrobust diff_vote_share_right_oppo dist_to_treated_boundary `if', c(0) `opts' covs(`covs') h(`bw' `bw')
	qui eststo rd201519_4_`i': rdrobust diff_turnout dist_to_treated_boundary `if', c(0) `opts' covs(`covs') h(`bw' `bw')
	local i = `i' + 1
}

capture mkdir "Tables"

esttab rd201519_1_1 rd201519_2_1 rd201519_3_1 rd201519_4_1 using "Tables/Table_B13.tex", label collabels(none) cells(b(star fmt(3) vacant({--})) se(par(( )) fmt(3))) stats() varlabel(RD_Estimate "LATE")  mgroups("\shortstack{$\Delta$ PiS\\Vote Share\\(2015-2019)}" "\shortstack{$\Delta$ Left Opposition\\Vote Share\\(2015-2019)}" "\shortstack{$\Delta$ Right Opposition\\Vote Share\\(2015-2019)}" "\shortstack{$\Delta$ Turnout\\(2015-2019)}", pattern(1 1 1 1) span erepeat(\cmidrule(lr){@span}) prefix(\multicolumn{@span}{c}{) suffix(})) prehead(`"\begin{table}[htbp]\centering\small"' `"\setlength\tabcolsep{0pt}"' `"\caption{@title}"' `"\label{table:pretreatment:balance:continuity}"' `"\begin{tabularx}{1.0\hsize}{l *{@E}{Y}}"' `"\toprule"') posthead("\\ \hline \\ \multicolumn{@span}{c}{\textbf{Panel A: 15-kilometer bandwidth}} \\\\[-1ex]") postfoot("")  title("Balance on Pre-treatment Characteristics Under Continuity Framework") eqlabels(none) booktabs replace prefoot("\\") nonumbers nomtitles noobs

esttab rd201519_1_2 rd201519_2_2 rd201519_3_2 rd201519_4_2 using "Tables/Table_B13.tex", f legend label collabels(none) cells(b(star fmt(3) vacant({--})) se(par(( )) fmt(3))) stats() varlabel(RD_Estimate "LATE")   posthead("\\ \hline \\ \multicolumn{@span}{c}{\textbf{Panel B: 20-kilometer bandwidth}} \\\\[-1ex]") booktabs append nonumbers nomtitles prefoot("\\") eqlabels(, begin(" " "") nofirst) noobs

esttab rd201519_1_3 rd201519_2_3 rd201519_3_3 rd201519_4_3 using "Tables/Table_B13.tex", f legend label collabels(none) cells(b(star fmt(3) vacant({--})) se(par(( )) fmt(3))) stats() varlabel(RD_Estimate "LATE")  posthead("\\ \hline \\ \multicolumn{@span}{c}{\textbf{Panel C: 25-kilometer bandwidth}} \\\\[-1ex]") postfoot(`"\\ \bottomrule"' `"\multicolumn{@span}{p{\linewidth}}{\footnotesize \emph{Notes}: Table presents results of a pre-treatment balance test under the continuity framework. All estimators are constructed using a zero-order local polynomial and a triangular kernel. Standard errors are reported in parentheses. * p$<$0.05, ** p$<$0.01, *** p$<$0.001}\\"' `"\end{tabularx}"' `"\end{table}"') booktabs append nonumbers  nomtitles prefoot("\\") eqlabels(, begin(" " "") nofirst) noobs

***********************************
***********************************
***********************************	



***********************************
**# Table B.14 : Results Using Continuity Framework
***********************************

frame change data2019_2023

local covs = ""
local if = "if partial_treated == 0"
local opts = "kernel(triangular) p(0)"

local i = 1
foreach bw in 15 20 25 {
	qui eststo rd201923_1_`i': rdrobust diff_vote_share_pis dist_to_treated_boundary `if', c(0) `opts' covs(`covs') h(`bw' `bw')
	qui eststo rd201923_2_`i':rdrobust diff_vote_share_left_oppo dist_to_treated_boundary `if', c(0) `opts' covs(`covs') h(`bw' `bw')
	qui eststo rd201923_3_`i':rdrobust diff_vote_share_right_oppo dist_to_treated_boundary `if', c(0) `opts' covs(`covs') h(`bw' `bw')
	qui eststo rd201923_4_`i': rdrobust diff_turnout dist_to_treated_boundary `if', c(0) `opts' covs(`covs') h(`bw' `bw')
	local i = `i' + 1
}

capture mkdir "Tables"

esttab rd201923_1_1 rd201923_2_1 rd201923_3_1 rd201923_4_1 using "Tables/Table_B14.tex", label collabels(none) cells(b(star fmt(3) vacant({--})) se(par(( )) fmt(3))) stats() varlabel(RD_Estimate "LATE")  mgroups("\shortstack{$\Delta$ PiS\\Vote Share\\(2019-2023)}" "\shortstack{$\Delta$ Left Opposition\\Vote Share\\(2019-2023)}" "\shortstack{$\Delta$ Right Opposition\\Vote Share\\(2019-2023)}" "\shortstack{$\Delta$ Turnout\\(2019-2023)}", pattern(1 1 1 1) span erepeat(\cmidrule(lr){@span}) prefix(\multicolumn{@span}{c}{) suffix(})) prehead(`"\begin{table}[htbp]\centering\small"' `"\setlength\tabcolsep{0pt}"' `"\caption{@title}"' `"\label{table:main:results:continuity}"' `"\begin{tabularx}{1.0\hsize}{l *{@E}{Y}}"' `"\toprule"') posthead("\\ \hline \\ \multicolumn{@span}{c}{\textbf{Panel A: 15-kilometer bandwidth}} \\\\[-1ex]") postfoot("")  title("Main Results Under Continuity Framework") eqlabels(none) booktabs replace prefoot("\\") nonumbers nomtitles noobs

esttab rd201923_1_2 rd201923_2_2 rd201923_3_2 rd201923_4_2 using "Tables/Table_B14.tex", f legend label collabels(none) cells(b(star fmt(3) vacant({--})) se(par(( )) fmt(3))) stats() varlabel(RD_Estimate "LATE")   posthead("\\ \hline \\ \multicolumn{@span}{c}{\textbf{Panel B: 20-kilometer bandwidth}} \\\\[-1ex]") booktabs append nonumbers nomtitles prefoot("\\") eqlabels(, begin(" " "") nofirst) noobs

esttab rd201923_1_3 rd201923_2_3 rd201923_3_3 rd201923_4_3 using "Tables/Table_B14.tex", f legend label collabels(none) cells(b(star fmt(3) vacant({--})) se(par(( )) fmt(3))) stats() varlabel(RD_Estimate "LATE")  posthead("\\ \hline \\ \multicolumn{@span}{c}{\textbf{Panel C: 25-kilometer bandwidth}} \\\\[-1ex]") postfoot(`"\\ \bottomrule"' `"\multicolumn{@span}{p{\linewidth}}{\footnotesize \emph{Notes}: Table presents main results replicated under the continuity framework. All estimators are constructed using a zero-order local polynomial and a triangular kernel. Standard errors are reported in parentheses. * p$<$0.05, ** p$<$0.01, *** p$<$0.001}\\"' `"\end{tabularx}"' `"\end{table}"') booktabs append nonumbers  nomtitles prefoot("\\") eqlabels(, begin(" " "") nofirst) noobs

***********************************
***********************************
***********************************	



*****************************************************************************
**#                          END OF DATA ANALYSIS                         ***
*****************************************************************************